1/*
2 * Copyright (C) 2016 Metrological Group B.V.
3 * Copyright (C) 2016 Igalia S.L.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "MediaKeys.h"
31
32#if ENABLE(ENCRYPTED_MEDIA)
33
34#include "CDM.h"
35#include "CDMClient.h"
36#include "CDMInstance.h"
37#include "Logging.h"
38#include "MediaKeySession.h"
39#include "SharedBuffer.h"
40
41namespace WebCore {
42
43MediaKeys::MediaKeys(bool useDistinctiveIdentifier, bool persistentStateAllowed, const Vector<MediaKeySessionType>& supportedSessionTypes, Ref<CDM>&& implementation, Ref<CDMInstance>&& instance)
44 : m_useDistinctiveIdentifier(useDistinctiveIdentifier)
45 , m_persistentStateAllowed(persistentStateAllowed)
46 , m_supportedSessionTypes(supportedSessionTypes)
47 , m_implementation(WTFMove(implementation))
48 , m_instance(WTFMove(instance))
49{
50}
51
52MediaKeys::~MediaKeys() = default;
53
54ExceptionOr<Ref<MediaKeySession>> MediaKeys::createSession(ScriptExecutionContext& context, MediaKeySessionType sessionType)
55{
56 // https://w3c.github.io/encrypted-media/#dom-mediakeys-setservercertificate
57 // W3C Editor's Draft 09 November 2016
58 LOG(EME, "EME - check if a new session can be created");
59
60 // When this method is invoked, the user agent must run the following steps:
61 // 1. If this object's supported session types value does not contain sessionType, throw [WebIDL] a NotSupportedError.
62 if (!m_supportedSessionTypes.contains(sessionType))
63 return Exception(NotSupportedError);
64
65 // 2. If the implementation does not support MediaKeySession operations in the current state, throw [WebIDL] an InvalidStateError.
66 if (!m_implementation->supportsSessions())
67 return Exception(InvalidStateError);
68
69 auto instanceSession = m_instance->createSession();
70 if (!instanceSession)
71 return Exception(InvalidStateError);
72
73 // 3. Let session be a new MediaKeySession object, and initialize it as follows:
74 // NOTE: Continued in MediaKeySession.
75 // 4. Return session.
76 auto session = MediaKeySession::create(context, makeWeakPtr(*this), sessionType, m_useDistinctiveIdentifier, m_implementation.copyRef(), instanceSession.releaseNonNull());
77 m_sessions.append(session.copyRef());
78 return session;
79}
80
81void MediaKeys::setServerCertificate(const BufferSource& serverCertificate, Ref<DeferredPromise>&& promise)
82{
83 // https://w3c.github.io/encrypted-media/#dom-mediakeys-setservercertificate
84 // W3C Editor's Draft 09 November 2016
85
86 // When this method is invoked, the user agent must run the following steps:
87 // 1. If the Key System implementation represented by this object's cdm implementation value does not support
88 // server certificates, return a promise resolved with false.
89 if (!m_implementation->supportsServerCertificates()) {
90 promise->resolve<IDLBoolean>(false);
91 return;
92 }
93
94 // 2. If serverCertificate is an empty array, return a promise rejected with a new a newly created TypeError.
95 if (!serverCertificate.length()) {
96 promise->reject(TypeError);
97 return;
98 }
99
100 // 3. Let certificate be a copy of the contents of the serverCertificate parameter.
101 auto certificate = SharedBuffer::create(serverCertificate.data(), serverCertificate.length());
102
103 // 4. Let promise be a new promise.
104 // 5. Run the following steps in parallel:
105
106 m_taskQueue.enqueueTask([this, certificate = WTFMove(certificate), promise = WTFMove(promise)] () mutable {
107 // 5.1. Use this object's cdm instance to process certificate.
108 if (m_instance->setServerCertificate(WTFMove(certificate)) == CDMInstance::Failed) {
109 // 5.2. If the preceding step failed, resolve promise with a new DOMException whose name is the appropriate error name.
110 promise->reject(InvalidStateError);
111 return;
112 }
113
114 // 5.1. Resolve promise with true.
115 promise->resolve<IDLBoolean>(true);
116 });
117
118 // 6. Return promise.
119}
120
121void MediaKeys::attachCDMClient(CDMClient& client)
122{
123 ASSERT(!m_cdmClients.contains(&client));
124 m_cdmClients.append(&client);
125}
126
127void MediaKeys::detachCDMClient(CDMClient& client)
128{
129 ASSERT(m_cdmClients.contains(&client));
130 m_cdmClients.removeFirst(&client);
131}
132
133void MediaKeys::attemptToResumePlaybackOnClients()
134{
135 for (auto* cdmClient : m_cdmClients)
136 cdmClient->cdmClientAttemptToResumePlaybackIfNecessary();
137}
138
139bool MediaKeys::hasOpenSessions() const
140{
141 return std::any_of(m_sessions.begin(), m_sessions.end(),
142 [](auto& session) {
143 return !session->isClosed();
144 });
145}
146
147} // namespace WebCore
148
149#endif // ENABLE(ENCRYPTED_MEDIA)
150