1/*
2 * Copyright (C) 2012-2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "PlugInAutoStartProvider.h"
28
29#include "APIArray.h"
30#include "APIDictionary.h"
31#include "WebContextClient.h"
32#include "WebProcessMessages.h"
33#include "WebProcessPool.h"
34#include <wtf/WallTime.h>
35
36namespace WebKit {
37using namespace WebCore;
38
39static const Seconds plugInAutoStartExpirationTimeThreshold { 30 * 24 * 60 * 60 };
40
41PlugInAutoStartProvider::PlugInAutoStartProvider(WebProcessPool* processPool)
42 : m_processPool(processPool)
43{
44 m_hashToOriginMap.add(PAL::SessionID::defaultSessionID(), HashMap<unsigned, String>());
45 m_autoStartTable.add(PAL::SessionID::defaultSessionID(), AutoStartTable());
46}
47
48static WallTime expirationTimeFromNow()
49{
50 return WallTime::now() + plugInAutoStartExpirationTimeThreshold;
51}
52
53void PlugInAutoStartProvider::addAutoStartOriginHash(const String& pageOrigin, unsigned plugInOriginHash, PAL::SessionID sessionID)
54{
55 auto sessionIterator = m_hashToOriginMap.find(sessionID);
56 if (sessionIterator == m_hashToOriginMap.end()) {
57 if (m_hashToOriginMap.get(PAL::SessionID::defaultSessionID()).contains(plugInOriginHash))
58 return;
59 sessionIterator = m_hashToOriginMap.set(sessionID, HashMap<unsigned, String>()).iterator;
60 } else if (sessionIterator->value.contains(plugInOriginHash) || m_hashToOriginMap.get(PAL::SessionID::defaultSessionID()).contains(plugInOriginHash))
61 return;
62
63 AutoStartTable::iterator it = m_autoStartTable.add(sessionID, AutoStartTable()).iterator->value.add(pageOrigin, PlugInAutoStartOriginMap()).iterator;
64
65 WallTime expirationTime = expirationTimeFromNow();
66 it->value.set(plugInOriginHash, expirationTime);
67 sessionIterator->value.set(plugInOriginHash, pageOrigin);
68
69 m_processPool->sendToAllProcesses(Messages::WebProcess::DidAddPlugInAutoStartOriginHash(plugInOriginHash, expirationTime, sessionID));
70
71 if (!sessionID.isEphemeral())
72 m_processPool->client().plugInAutoStartOriginHashesChanged(m_processPool);
73}
74
75SessionPlugInAutoStartOriginMap PlugInAutoStartProvider::autoStartOriginHashesCopy() const
76{
77 SessionPlugInAutoStartOriginMap sessionMap;
78
79 for (const auto& sessionKeyOriginHash : m_autoStartTable) {
80 PlugInAutoStartOriginMap& map = sessionMap.add(sessionKeyOriginHash.key, PlugInAutoStartOriginMap()).iterator->value;
81 for (const auto& keyOriginHash : sessionKeyOriginHash.value) {
82 for (const auto& originHash : keyOriginHash.value)
83 map.set(originHash.key, originHash.value);
84 }
85 }
86 return sessionMap;
87}
88
89Ref<API::Dictionary> PlugInAutoStartProvider::autoStartOriginsTableCopy() const
90{
91 API::Dictionary::MapType map;
92
93 WallTime now = WallTime::now();
94 for (const auto& stringOriginHash : m_autoStartTable.get(PAL::SessionID::defaultSessionID())) {
95 API::Dictionary::MapType hashMap;
96 for (const auto& originHash : stringOriginHash.value) {
97 if (now <= originHash.value)
98 hashMap.set(String::number(originHash.key), API::Double::create(originHash.value.secondsSinceEpoch().seconds()));
99 }
100 if (hashMap.size())
101 map.set(stringOriginHash.key, API::Dictionary::create(WTFMove(hashMap)));
102 }
103
104 return API::Dictionary::create(WTFMove(map));
105}
106
107void PlugInAutoStartProvider::setAutoStartOriginsTable(API::Dictionary& table)
108{
109 setAutoStartOriginsTableWithItemsPassingTest(table, [](WallTime) {
110 return true;
111 });
112}
113
114void PlugInAutoStartProvider::setAutoStartOriginsFilteringOutEntriesAddedAfterTime(API::Dictionary& table, WallTime time)
115{
116 WallTime adjustedTimestamp = time + plugInAutoStartExpirationTimeThreshold;
117 setAutoStartOriginsTableWithItemsPassingTest(table, [adjustedTimestamp](WallTime expirationTimestamp) {
118 return adjustedTimestamp > expirationTimestamp;
119 });
120}
121
122void PlugInAutoStartProvider::setAutoStartOriginsTableWithItemsPassingTest(API::Dictionary& table, WTF::Function<bool(WallTime expirationTimestamp)>&& isExpirationTimeAcceptable)
123{
124 ASSERT(isExpirationTimeAcceptable);
125
126 m_hashToOriginMap.clear();
127 m_autoStartTable.clear();
128 HashMap<unsigned, WallTime> hashMap;
129 HashMap<unsigned, String>& hashToOriginMap = m_hashToOriginMap.add(PAL::SessionID::defaultSessionID(), HashMap<unsigned, String>()).iterator->value;
130 AutoStartTable& ast = m_autoStartTable.add(PAL::SessionID::defaultSessionID(), AutoStartTable()).iterator->value;
131
132 for (auto& strDict : table.map()) {
133 PlugInAutoStartOriginMap hashes;
134 for (auto& hashTime : static_cast<API::Dictionary*>(strDict.value.get())->map()) {
135 bool ok;
136 unsigned hash = hashTime.key.toUInt(&ok);
137 if (!ok)
138 continue;
139
140 if (hashTime.value->type() != API::Double::APIType)
141 continue;
142
143 WallTime expirationTime = WallTime::fromRawSeconds(static_cast<API::Double*>(hashTime.value.get())->value());
144 if (!isExpirationTimeAcceptable(expirationTime))
145 continue;
146
147 hashes.set(hash, expirationTime);
148 hashMap.set(hash, expirationTime);
149 hashToOriginMap.set(hash, strDict.key);
150 }
151
152 if (!hashes.isEmpty())
153 ast.set(strDict.key, hashes);
154 }
155
156 m_processPool->sendToAllProcesses(Messages::WebProcess::ResetPlugInAutoStartOriginDefaultHashes(hashMap));
157}
158
159void PlugInAutoStartProvider::setAutoStartOriginsArray(API::Array& originList)
160{
161 m_autoStartOrigins.clear();
162 for (auto string : originList.elementsOfType<API::String>())
163 m_autoStartOrigins.append(string->string());
164}
165
166void PlugInAutoStartProvider::didReceiveUserInteraction(unsigned plugInOriginHash, PAL::SessionID sessionID)
167{
168 HashMap<PAL::SessionID, HashMap<unsigned, String>>::const_iterator sessionIterator = m_hashToOriginMap.find(sessionID);
169 HashMap<unsigned, String>::const_iterator it;
170 bool contains = false;
171 if (sessionIterator != m_hashToOriginMap.end()) {
172 it = sessionIterator->value.find(plugInOriginHash);
173 contains = it != sessionIterator->value.end();
174 }
175 if (!contains) {
176 sessionIterator = m_hashToOriginMap.find(PAL::SessionID::defaultSessionID());
177 it = sessionIterator->value.find(plugInOriginHash);
178 if (it == sessionIterator->value.end()) {
179 ASSERT_NOT_REACHED();
180 return;
181 }
182 }
183
184 WallTime newExpirationTime = expirationTimeFromNow();
185 m_autoStartTable.add(sessionID, AutoStartTable()).iterator->value.add(it->value, PlugInAutoStartOriginMap()).iterator->value.set(plugInOriginHash, newExpirationTime);
186 m_processPool->sendToAllProcesses(Messages::WebProcess::DidAddPlugInAutoStartOriginHash(plugInOriginHash, newExpirationTime, sessionID));
187 m_processPool->client().plugInAutoStartOriginHashesChanged(m_processPool);
188}
189
190} // namespace WebKit
191