1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004-2006, 2010, 2012-2016 Apple Inc. All rights reserved.
6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "HTMLKeygenElement.h"
27
28#include "Attribute.h"
29#include "DOMFormData.h"
30#include "Document.h"
31#include "ElementChildIterator.h"
32#include "HTMLNames.h"
33#include "HTMLSelectElement.h"
34#include "HTMLOptionElement.h"
35#include "SSLKeyGenerator.h"
36#include "ShadowRoot.h"
37#include "Text.h"
38#include <wtf/IsoMallocInlines.h>
39#include <wtf/NeverDestroyed.h>
40#include <wtf/StdLibExtras.h>
41
42namespace WebCore {
43
44WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLKeygenElement);
45
46using namespace HTMLNames;
47
48class KeygenSelectElement final : public HTMLSelectElement {
49 WTF_MAKE_ISO_ALLOCATED_INLINE(KeygenSelectElement);
50public:
51 static Ref<KeygenSelectElement> create(Document& document)
52 {
53 return adoptRef(*new KeygenSelectElement(document));
54 }
55
56protected:
57 KeygenSelectElement(Document& document)
58 : HTMLSelectElement(selectTag, document, 0)
59 {
60 static NeverDestroyed<AtomicString> pseudoId("-webkit-keygen-select", AtomicString::ConstructFromLiteral);
61 setPseudo(pseudoId);
62 }
63
64private:
65 Ref<Element> cloneElementWithoutAttributesAndChildren(Document& targetDocument) override
66 {
67 return create(targetDocument);
68 }
69};
70
71inline HTMLKeygenElement::HTMLKeygenElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
72 : HTMLFormControlElementWithState(tagName, document, form)
73{
74 ASSERT(hasTagName(keygenTag));
75
76 // Create a select element with one option element for each key size.
77 Vector<String> keys;
78 getSupportedKeySizes(keys);
79
80 auto select = KeygenSelectElement::create(document);
81 for (auto& key : keys) {
82 auto option = HTMLOptionElement::create(document);
83 select->appendChild(option);
84 option->appendChild(Text::create(document, key));
85 }
86
87 ensureUserAgentShadowRoot().appendChild(select);
88}
89
90Ref<HTMLKeygenElement> HTMLKeygenElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
91{
92 return adoptRef(*new HTMLKeygenElement(tagName, document, form));
93}
94
95void HTMLKeygenElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
96{
97 // Reflect disabled attribute on the shadow select element
98 if (name == disabledAttr)
99 shadowSelect()->setAttribute(name, value);
100
101 HTMLFormControlElement::parseAttribute(name, value);
102}
103
104bool HTMLKeygenElement::isKeytypeRSA() const
105{
106 const auto& keyType = attributeWithoutSynchronization(keytypeAttr);
107 return keyType.isNull() || equalLettersIgnoringASCIICase(keyType, "rsa");
108}
109
110void HTMLKeygenElement::setKeytype(const AtomicString& value)
111{
112 setAttributeWithoutSynchronization(keytypeAttr, value);
113}
114
115String HTMLKeygenElement::keytype() const
116{
117 return isKeytypeRSA() ? "rsa"_s : emptyString();
118}
119
120bool HTMLKeygenElement::appendFormData(DOMFormData& formData, bool)
121{
122 // Only RSA is supported at this time.
123 if (!isKeytypeRSA())
124 return false;
125 auto value = document().signedPublicKeyAndChallengeString(shadowSelect()->selectedIndex(), attributeWithoutSynchronization(challengeAttr), document().baseURL());
126 if (value.isNull())
127 return false;
128 formData.append(name(), value);
129 return true;
130}
131
132const AtomicString& HTMLKeygenElement::formControlType() const
133{
134 static NeverDestroyed<const AtomicString> keygen("keygen", AtomicString::ConstructFromLiteral);
135 return keygen;
136}
137
138void HTMLKeygenElement::reset()
139{
140 static_cast<HTMLFormControlElement*>(shadowSelect())->reset();
141}
142
143bool HTMLKeygenElement::shouldSaveAndRestoreFormControlState() const
144{
145 return false;
146}
147
148HTMLSelectElement* HTMLKeygenElement::shadowSelect() const
149{
150 auto root = userAgentShadowRoot();
151 if (!root)
152 return nullptr;
153
154 return childrenOfType<HTMLSelectElement>(*root).first();
155}
156
157} // namespace
158