123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/permissions/permission_auditing_database.h"
- #include <algorithm>
- #include <iostream>
- #include <limits>
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/check.h"
- #include "base/files/file_path.h"
- #include "sql/database.h"
- #include "sql/meta_table.h"
- #include "sql/statement.h"
- #include "sql/transaction.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "url/gurl.h"
- namespace permissions {
- namespace {
- // For this database, schema migration is supported for at least 1 year.
- // This means we can deprecate old versions that landed more than a year ago.
- //
- // Version 1: https://crrev.com/c/2435307 - 2020-11-04
- // The current number of the database schema.
- constexpr int kVersion = 1;
- // The lowest version of the database schema such that a legacy code can still
- // read/write the current database.
- constexpr int kCompatibleVersion = 1;
- } // namespace
- PermissionAuditingDatabase::PermissionAuditingDatabase() = default;
- PermissionAuditingDatabase::~PermissionAuditingDatabase() = default;
- bool PermissionAuditingDatabase::Init(const base::FilePath& path) {
- db_.set_histogram_tag("Permission Auditing Logs");
- if (!db_.Open(path)) {
- return false;
- }
- sql::MetaTable metatable;
- if (!metatable.Init(&db_, kVersion, kCompatibleVersion)) {
- db_.Poison();
- return false;
- }
- if (metatable.GetCompatibleVersionNumber() > kVersion) {
- db_.Poison();
- return false;
- }
- if (!db_.DoesTableExist("uses")) {
- if (!CreateSchema()) {
- db_.Poison();
- return false;
- }
- }
- // TODO(anyone): perform migration if metatable.GetVersionNumber() < kVersion
- return true;
- }
- bool PermissionAuditingDatabase::CreateSchema() {
- sql::Transaction transaction(&db_);
- if (!transaction.Begin()) {
- return false;
- }
- if (!db_.Execute("CREATE TABLE uses("
- " id INTEGER PRIMARY KEY AUTOINCREMENT,"
- " origin TEXT NOT NULL,"
- " content_setting_type INTEGER NOT NULL,"
- " usage_start_time INTEGER NOT NULL,"
- " usage_end_time INTEGER NOT NULL,"
- " had_user_activation INTEGER NOT NULL,"
- " was_foreground INTEGER NOT NULL,"
- " had_focus INTEGER NOT NULL"
- ")")) {
- return false;
- }
- if (!db_.Execute("CREATE UNIQUE INDEX setting_origin_start_time ON "
- "uses(origin, content_setting_type,"
- "usage_start_time)")) {
- return false;
- }
- if (!db_.Execute("CREATE INDEX setting_origin_end_time ON "
- "uses(origin, content_setting_type,"
- "usage_end_time)")) {
- return false;
- }
- if (!db_.Execute("CREATE INDEX start_time ON "
- "uses(usage_start_time)")) {
- return false;
- }
- if (!db_.Execute("CREATE INDEX end_time ON "
- "uses(usage_end_time)")) {
- return false;
- }
- return transaction.Commit();
- }
- bool PermissionAuditingDatabase::StorePermissionUsage(
- const PermissionUsageSession& session) {
- DCHECK(session.IsValid());
- sql::Statement statement(
- db_.GetCachedStatement(SQL_FROM_HERE,
- "INSERT INTO uses(origin, content_setting_type,"
- "usage_start_time, usage_end_time,"
- "had_user_activation, was_foreground, had_focus)"
- "VALUES (?, ?, ?, ?, ?, ?, ?)"));
- statement.BindString(0, session.origin.Serialize());
- statement.BindInt(1, static_cast<int32_t>(session.type));
- statement.BindTime(2, session.usage_start);
- statement.BindTime(3, session.usage_end);
- statement.BindBool(4, session.had_user_activation);
- statement.BindBool(5, session.was_foreground);
- statement.BindBool(6, session.had_focus);
- sql::Transaction transaction(&db_);
- if (!transaction.Begin()) {
- return false;
- }
- if (!statement.Run()) {
- return false;
- }
- return transaction.Commit();
- }
- std::vector<PermissionUsageSession>
- PermissionAuditingDatabase::GetPermissionUsageHistory(ContentSettingsType type,
- const url::Origin& origin,
- base::Time start_time) {
- DCHECK(!origin.opaque());
- std::vector<PermissionUsageSession> sessions;
- sql::Statement statement(db_.GetCachedStatement(
- SQL_FROM_HERE,
- "SELECT usage_start_time, usage_end_time, had_user_activation,"
- "was_foreground, had_focus "
- "FROM uses "
- "WHERE origin = ? AND content_setting_type = ? "
- "AND usage_end_time >= ?"));
- statement.BindString(0, origin.Serialize());
- statement.BindInt(1, static_cast<int32_t>(type));
- statement.BindTime(2, start_time.is_null() ? base::Time::Min() : start_time);
- while (statement.Step()) {
- sessions.push_back({.origin = origin,
- .type = type,
- .usage_start = statement.ColumnTime(0),
- .usage_end = statement.ColumnTime(1),
- .had_user_activation = statement.ColumnBool(2),
- .was_foreground = statement.ColumnBool(3),
- .had_focus = statement.ColumnBool(4)});
- }
- return sessions;
- }
- absl::optional<base::Time>
- PermissionAuditingDatabase::GetLastPermissionUsageTime(
- ContentSettingsType type,
- const url::Origin& origin) {
- DCHECK(!origin.opaque());
- sql::Statement statement(
- db_.GetCachedStatement(SQL_FROM_HERE,
- "SELECT usage_end_time "
- "FROM uses "
- "WHERE origin = ? AND content_setting_type = ? "
- "ORDER BY usage_end_time DESC "
- "LIMIT 1"));
- statement.BindString(0, origin.Serialize());
- statement.BindInt(1, static_cast<int32_t>(type));
- absl::optional<base::Time> last_usage;
- if (statement.Step()) {
- last_usage = statement.ColumnTime(0);
- }
- return last_usage;
- }
- bool PermissionAuditingDatabase::UpdateEndTime(ContentSettingsType type,
- const url::Origin& origin,
- base::Time start_time,
- base::Time new_end_time) {
- DCHECK(!origin.opaque());
- DCHECK(!start_time.is_null());
- DCHECK(!new_end_time.is_null());
- DCHECK_LE(start_time, new_end_time);
- sql::Statement statement(
- db_.GetCachedStatement(SQL_FROM_HERE,
- "UPDATE uses "
- "SET usage_end_time = ? "
- "WHERE origin = ? AND content_setting_type = ? "
- "AND usage_start_time = ?"));
- statement.BindTime(0, new_end_time);
- statement.BindString(1, origin.Serialize());
- statement.BindInt(2, static_cast<int32_t>(type));
- statement.BindTime(3, start_time);
- sql::Transaction transaction(&db_);
- if (!transaction.Begin()) {
- return false;
- }
- if (!statement.Run()) {
- return false;
- }
- return transaction.Commit();
- }
- bool PermissionAuditingDatabase::DeleteSessionsBetween(base::Time start_time,
- base::Time end_time) {
- std::vector<int> ids;
- sql::Statement statement(
- db_.GetCachedStatement(SQL_FROM_HERE,
- "DELETE FROM uses "
- "WHERE usage_start_time BETWEEN ? AND ? "
- "OR usage_end_time BETWEEN ? AND ?"));
- statement.BindTime(0, start_time.is_null() ? base::Time::Min() : start_time);
- statement.BindTime(1, end_time.is_null() ? base::Time::Max() : end_time);
- statement.BindTime(2, start_time.is_null() ? base::Time::Min() : start_time);
- statement.BindTime(3, end_time.is_null() ? base::Time::Max() : end_time);
- sql::Transaction transaction(&db_);
- if (!transaction.Begin()) {
- return false;
- }
- if (!statement.Run()) {
- return false;
- }
- return transaction.Commit();
- }
- } // namespace permissions
|