View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
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    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.crypto;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.BrowserRunner;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.htmlunit.junit.annotation.HtmlUnitNYI;
21  import org.junit.Test;
22  import org.junit.runner.RunWith;
23  
24  /**
25   * Tests for {@link SubtleCrypto}.
26   *
27   * @author Ahmed Ashour
28   * @author Ronald Brill
29   * @author Atsushi Nakagawa
30   */
31  @RunWith(BrowserRunner.class)
32  public class SubtleCryptoTest extends WebDriverTestCase {
33  
34      /**
35       * @throws Exception if the test fails
36       */
37      @Test
38      @Alerts({"function", "TypeError"})
39      public void ctor() throws Exception {
40          final String html = DOCTYPE_HTML
41              + "<html>\n"
42              + "<head>\n"
43              + "  <script>\n"
44              + LOG_TEXTAREA_FUNCTION
45  
46              + "    function test() {\n"
47              + "      try {\n"
48              + "        log(typeof SubtleCrypto);\n"
49              + "        new SubtleCrypto();\n"
50              + "      } catch(e) { logEx(e); }\n"
51              + "    }\n"
52              + "  </script>\n"
53              + "</head>\n"
54              + "<body onload='test()'>\n"
55              + LOG_TEXTAREA
56              + "</body>\n"
57              + "</html>";
58  
59          loadPageVerifyTextArea2(html);
60      }
61  
62      /**
63       * Methods in SubtleCrypto should always wraps errors in a Promise and never throw directly.
64       * @throws Exception if the test fails
65       */
66      @Test
67      @Alerts("TypeError true")
68      @HtmlUnitNYI(CHROME = "TypeError false",
69              EDGE = "TypeError false",
70              FF = "TypeError false",
71              FF_ESR = "TypeError false")
72      public void unsupportedCall() throws Exception {
73          final String html = DOCTYPE_HTML
74              + "<html><head><script>\n"
75              + LOG_TITLE_FUNCTION
76              + "  function test() {\n"
77              + "    if (window.crypto) {\n"
78              + "      window.crypto.subtle.generateKey(\n"
79              + "        { name: 'x' }\n"
80              + "      )\n"
81              + "      .catch(function(e) {\n"
82              + "        log('TypeError ' + (e instanceof TypeError));\n"
83              + "      });\n"
84              + "    }\n"
85              + "  }\n"
86              + "</script></head><body onload='test()'>\n"
87              + "</body></html>";
88  
89          loadPage2(html, URL_FIRST);
90          verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
91      }
92  
93      /**
94       * @throws Exception if the test fails
95       */
96      @Test
97      @Alerts({"[object Crypto]", "public", "true", "verify",
98               "name RSASSA-PKCS1-v1_5", "hash [object Object]", "modulusLength 2048",
99               "publicExponent 1,0,1",
100              "private", "false", "sign",
101              "name RSASSA-PKCS1-v1_5", "hash [object Object]", "modulusLength 2048",
102              "publicExponent 1,0,1", "done"})
103     @HtmlUnitNYI(CHROME = {"[object Crypto]", "[object DOMException]"},
104             EDGE = {"[object Crypto]", "[object DOMException]"},
105             FF = {"[object Crypto]", "[object DOMException]"},
106             FF_ESR = {"[object Crypto]", "[object DOMException]"})
107     public void rsassa() throws Exception {
108         final String html = DOCTYPE_HTML
109             + "<html><head><script>\n"
110             + LOG_TITLE_FUNCTION
111             + "  function test() {\n"
112             + "    log(window.crypto);\n"
113             + "    if (window.crypto) {\n"
114             + "      window.crypto.subtle.generateKey(\n"
115             + "        {\n"
116             + "          name: 'RSASSA-PKCS1-v1_5',\n"
117             + "          modulusLength: 2048,\n"
118             + "          publicExponent: new Uint8Array([0x01, 0x00, 0x01]),\n"
119             + "          hash: {name: 'SHA-256'}\n"
120             + "        },\n"
121             + "        false, //whether the key is extractable (i.e. can be used in exportKey)\n"
122             + "        ['sign', 'verify']\n"
123             + "      )\n"
124             + "      .then(function(key) {\n"
125             + "        log(key.publicKey.type);\n"
126             + "        log(key.publicKey.extractable);\n"
127             + "        log(key.publicKey.usages);\n"
128             + "        for(var x in key.publicKey.algorithm) {\n"
129             + "          log(x + ' ' + key.publicKey.algorithm[x]);\n"
130             + "        }\n"
131             + "        log(key.privateKey.type);\n"
132             + "        log(key.privateKey.extractable);\n"
133             + "        log(key.privateKey.usages);\n"
134             + "        for(var x in key.privateKey.algorithm) {\n"
135             + "          log(x + ' ' + key.publicKey.algorithm[x]);\n"
136             + "        }\n"
137             + "        log('done');\n"
138             + "      })\n"
139             + "      .catch(function(err) {\n"
140             + "        log(err);\n"
141             + "      });\n"
142             + "    } else { log('no window.crypto'); }\n"
143             + "  }\n"
144             + "</script></head><body onload='test()'>\n"
145             + "</body></html>";
146 
147         loadPage2(html);
148         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
149     }
150 }