Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 94740e6c authored by Selim Gurun's avatar Selim Gurun
Browse files

Control access to inherited methods of jsinterface objects

Bug: 7073422

Create the plumbing to use an annotation to allow access to
inherited methods of jsinterface objects. The default webview
behavior has not changed yet. However internally an a flag is
introduced to restrict javascript access to methods that have an annotation.

Change-Id: I41927248e6bc4b09d17c0707c60fe5e6ab681e66
parent bdf8fa0c
Loading
Loading
Loading
Loading
+42 −12
Original line number Diff line number Diff line
@@ -89,8 +89,19 @@ class BrowserFrame extends Handler {
    // Is this frame the main frame?
    private boolean mIsMainFrame;

    // Javascript interface object
    private class JSObject {
        Object object;
        boolean requireAnnotation;

        public JSObject(Object object, boolean requireAnnotation) {
            this.object = object;
            this.requireAnnotation = requireAnnotation;
        }
    }

    // Attached Javascript interfaces
    private Map<String, Object> mJavaScriptObjects;
    private Map<String, JSObject> mJavaScriptObjects;
    private Set<Object> mRemovedJavaScriptObjects;

    // Key store handler when Chromium HTTP stack is used.
@@ -234,10 +245,8 @@ class BrowserFrame extends Handler {
        }
        sConfigCallback.addHandler(this);

        mJavaScriptObjects = javascriptInterfaces;
        if (mJavaScriptObjects == null) {
            mJavaScriptObjects = new HashMap<String, Object>();
        }
        mJavaScriptObjects = new HashMap<String, JSObject>();
        addJavaScriptObjects(javascriptInterfaces);
        mRemovedJavaScriptObjects = new HashSet<Object>();

        mSettings = settings;
@@ -590,15 +599,36 @@ class BrowserFrame extends Handler {
        Iterator<String> iter = mJavaScriptObjects.keySet().iterator();
        while (iter.hasNext())  {
            String interfaceName = iter.next();
            Object object = mJavaScriptObjects.get(interfaceName);
            if (object != null) {
            JSObject jsobject = mJavaScriptObjects.get(interfaceName);
            if (jsobject != null && jsobject.object != null) {
                nativeAddJavascriptInterface(nativeFramePointer,
                        mJavaScriptObjects.get(interfaceName), interfaceName);
                        jsobject.object, interfaceName, jsobject.requireAnnotation);
            }
        }
        mRemovedJavaScriptObjects.clear();
    }

    /*
     * Add javascript objects to the internal list of objects. The default behavior
     * is to allow access to inherited methods (no annotation needed). This is only
     * used when js objects are passed through a constructor (via a hidden constructor).
     *
     * @TODO change the default behavior to be compatible with the public addjavascriptinterface
     */
    private void addJavaScriptObjects(Map<String, Object> javascriptInterfaces) {

        // TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above.
        if (javascriptInterfaces == null) return;
        Iterator<String> iter = javascriptInterfaces.keySet().iterator();
        while (iter.hasNext())  {
            String interfaceName = iter.next();
            Object object = javascriptInterfaces.get(interfaceName);
            if (object != null) {
                mJavaScriptObjects.put(interfaceName, new JSObject(object, false));
            }
        }
    }

    /**
     * This method is called by WebCore to check whether application
     * wants to hijack url loading
@@ -616,11 +646,11 @@ class BrowserFrame extends Handler {
        }
    }

    public void addJavascriptInterface(Object obj, String interfaceName) {
    public void addJavascriptInterface(Object obj, String interfaceName,
            boolean requireAnnotation) {
        assert obj != null;
        removeJavascriptInterface(interfaceName);

        mJavaScriptObjects.put(interfaceName, obj);
        mJavaScriptObjects.put(interfaceName, new JSObject(obj, requireAnnotation));
    }

    public void removeJavascriptInterface(String interfaceName) {
@@ -1245,7 +1275,7 @@ class BrowserFrame extends Handler {
     * Add a javascript interface to the main frame.
     */
    private native void nativeAddJavascriptInterface(int nativeFramePointer,
            Object obj, String interfaceName);
            Object obj, String interfaceName, boolean requireAnnotation);

    public native void clearCache();

+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.webkit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotation that allows exposing methods to JavaScript. Starting from API level
 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} and above, only methods explicitly
 * marked with this annotation are available to the Javascript code. See
 * {@link android.webkit.Webview#addJavaScriptInterface} for more information about it.
 *
 * @hide
 */
@SuppressWarnings("javadoc")
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface JavascriptInterface {
}
 No newline at end of file
+4 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.graphics.Picture;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.http.SslCertificate;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.os.Message;
@@ -1507,6 +1508,9 @@ public class WebView extends AbsoluteLayout
    public void addJavascriptInterface(Object object, String name) {
        checkThread();
        mProvider.addJavascriptInterface(object, name);
        // TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above. Don't forget to
        // update the doc, set a link to annotation and unhide the annotation.
        // also describe that fields of java objects are not accessible from JS.
    }

    /**
+3 −0
Original line number Diff line number Diff line
@@ -4114,12 +4114,15 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
     */
    @Override
    public void addJavascriptInterface(Object object, String name) {

        if (object == null) {
            return;
        }
        WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
        // TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above.
        arg.mObject = object;
        arg.mInterfaceName = name;
        arg.mRequireAnnotation = false;
        mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
    }

+2 −1
Original line number Diff line number Diff line
@@ -824,6 +824,7 @@ public final class WebViewCore {
    static class JSInterfaceData {
        Object mObject;
        String mInterfaceName;
        boolean mRequireAnnotation;
    }

    static class JSKeyData {
@@ -1489,7 +1490,7 @@ public final class WebViewCore {
                        case ADD_JS_INTERFACE:
                            JSInterfaceData jsData = (JSInterfaceData) msg.obj;
                            mBrowserFrame.addJavascriptInterface(jsData.mObject,
                                    jsData.mInterfaceName);
                                    jsData.mInterfaceName, jsData.mRequireAnnotation);
                            break;

                        case REMOVE_JS_INTERFACE: