1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.webkit;
18 
19 import android.webkit.WebView;
20 
21 import androidx.annotation.IntDef;
22 import androidx.annotation.RequiresFeature;
23 import androidx.annotation.RestrictTo;
24 
25 import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
26 import org.jspecify.annotations.NonNull;
27 
28 import java.lang.annotation.ElementType;
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.lang.annotation.Target;
32 import java.util.HashMap;
33 import java.util.Map;
34 import java.util.Set;
35 
36 /**
37  * Configuration to set API enablement status for site origins through override rules.
38  *
39  * <p>Websites will follow the default status supplied in the builder constructor,
40  * unless the site origin matches one of the origin patterns supplied in the override rules.
41  *
42  * <p>The override rules are a map from origin patterns to the desired
43  * {@link WebViewMediaIntegrityApiStatus}.
44  */
45 @RequiresFeature(name = WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS,
46         enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
47 public class WebViewMediaIntegrityApiStatusConfig {
48     @Target(ElementType.TYPE_USE)
49     @IntDef({WEBVIEW_MEDIA_INTEGRITY_API_DISABLED,
50             WEBVIEW_MEDIA_INTEGRITY_API_ENABLED_WITHOUT_APP_IDENTITY,
51             WEBVIEW_MEDIA_INTEGRITY_API_ENABLED})
52     @RestrictTo(RestrictTo.Scope.LIBRARY)
53     @Retention(RetentionPolicy.SOURCE)
54     @interface WebViewMediaIntegrityApiStatus {
55     }
56 
57     /**
58      * Enables the WebView Media Integrity API and allows sharing of the app package name with
59      * the JavaScript caller.
60      *
61      * <p>This is the default value.
62      */
63     public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED =
64             WebSettingsBoundaryInterface.WebViewMediaIntegrityApiStatus.ENABLED;
65 
66     /**
67      * Enables the WebView Media Integrity API for JavaScript callers but disables sharing app
68      * package name in generated tokens.
69      */
70     public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED_WITHOUT_APP_IDENTITY =
71             WebSettingsBoundaryInterface.WebViewMediaIntegrityApiStatus
72                     .ENABLED_WITHOUT_APP_IDENTITY;
73 
74     /**
75      * Disables the WebView Media Integrity API and causes it to return an
76      * error code to the JavaScript callers indicating that the app has disabled it.
77      */
78     public static final int WEBVIEW_MEDIA_INTEGRITY_API_DISABLED =
79             WebSettingsBoundaryInterface.WebViewMediaIntegrityApiStatus.DISABLED;
80 
81     private final @WebViewMediaIntegrityApiStatus int mDefaultStatus;
82     private final Map<String, @WebViewMediaIntegrityApiStatus Integer> mOverrideRules;
83 
WebViewMediaIntegrityApiStatusConfig(@onNull Builder builder)84     public WebViewMediaIntegrityApiStatusConfig(@NonNull Builder builder) {
85         this.mDefaultStatus = builder.mDefaultStatus;
86         this.mOverrideRules = builder.mOverrideRules;
87     }
88 
89     /**
90      * Builds a {@link WebViewMediaIntegrityApiStatusConfig} having a default API status and
91      * a map of origin pattern rules to their respective API status.
92      *
93      * <p>
94      * Example:
95      * <pre class="prettyprint">
96      *     // Create a config with default API status being DISABLED and API status is ENABLED for
97      *     // Uris matching origin pattern "http://*.example.com"
98      *     new WebViewMediaIntegrityApiStatusConfig.Builder(WEBVIEW_MEDIA_INTEGRITY_API_DISABLED)
99      *         .addOverrideRule("http://*.example.com", WEBVIEW_MEDIA_INTEGRITY_API_ENABLED)
100      *         .build();
101      * </pre>
102      */
103     public static final class Builder {
104         private final @WebViewMediaIntegrityApiStatus int mDefaultStatus;
105         private Map<String, @WebViewMediaIntegrityApiStatus Integer> mOverrideRules;
106 
107         /**
108          * @param defaultStatus Default API status that will be used for URIs that don't match
109          *                      any origin pattern rule.
110          */
Builder(@ebViewMediaIntegrityApiStatus int defaultStatus)111         public Builder(@WebViewMediaIntegrityApiStatus int defaultStatus) {
112             this.mDefaultStatus = defaultStatus;
113             this.mOverrideRules = new HashMap<>();
114         }
115 
116         /**
117          * Add an override rule to set a specific API status for origin sites matching the origin
118          * pattern stated in the rule. Origin patterns should be supplied in the same format as
119          * those in
120          * {@link androidx.webkit.WebViewCompat.WebMessageListener#addWebMessageListener(WebView, String, Set, WebViewCompat.WebMessageListener)}
121          *
122          * If two or more origin patterns match a given origin site, the least permissive option
123          * will be chosen.
124          */
125 
addOverrideRule(@onNull String originPattern, @WebViewMediaIntegrityApiStatus int permission)126         public @NonNull Builder addOverrideRule(@NonNull String originPattern,
127                 @WebViewMediaIntegrityApiStatus int permission) {
128             mOverrideRules.put(originPattern, permission);
129             return this;
130         }
131 
132         /**
133          * Set all required override rules at once using a map of origin patterns to
134          * desired API statuses. This overwrites existing rules.
135          * <p>
136          * If two or more origin patterns match a given origin site, the least permissive option
137          * will be chosen.
138          * <p>
139          * This is only meant for internal use within the library.
140          */
141         @RestrictTo(RestrictTo.Scope.LIBRARY)
setOverrideRules(@onNull Map<String, @WebViewMediaIntegrityApiStatus Integer> overrideRules)142         public @NonNull Builder setOverrideRules(@NonNull Map<String,
143                 @WebViewMediaIntegrityApiStatus Integer> overrideRules) {
144             mOverrideRules = overrideRules;
145             return this;
146         }
147 
148         /**
149          * Build the config.
150          */
build()151         public @NonNull WebViewMediaIntegrityApiStatusConfig build() {
152             return new WebViewMediaIntegrityApiStatusConfig(this);
153         }
154     }
155 
156     /**
157      * Returns the default value for origins that don't match any override rules.
158      */
getDefaultStatus()159     public @WebViewMediaIntegrityApiStatus int getDefaultStatus() {
160         return mDefaultStatus;
161     }
162 
163     /**
164      * Get the explicitly set override rules.
165      * <p> This is a map from origin patterns to their desired WebView Media Integrity API statuses.
166      *
167      */
getOverrideRules()168     public @NonNull Map<String, @WebViewMediaIntegrityApiStatus Integer> getOverrideRules() {
169         return mOverrideRules;
170     }
171 }
172