普通文本  |  164行  |  4.8 KB

// Copyright 2016 The Weave 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 "src/access_black_list_manager_impl.h"

#include <base/json/json_reader.h>
#include <base/json/json_writer.h>
#include <base/values.h>

#include "src/commands/schema_constants.h"
#include "src/data_encoding.h"

namespace weave {

namespace {
const char kConfigFileName[] = "black_list";

const char kUser[] = "user";
const char kApp[] = "app";
const char kExpiration[] = "expiration";
}

AccessBlackListManagerImpl::AccessBlackListManagerImpl(
    provider::ConfigStore* store,
    size_t capacity,
    base::Clock* clock)
    : capacity_{capacity}, clock_{clock}, store_{store} {
  Load();
}

void AccessBlackListManagerImpl::Load() {
  if (!store_)
    return;
  if (auto list = base::ListValue::From(
          base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) {
    for (const auto& e : *list) {
      const base::DictionaryValue* entry{nullptr};
      std::string user;
      std::string app;
      decltype(entries_)::key_type key;
      int expiration;
      if (e->GetAsDictionary(&entry) && entry->GetString(kUser, &user) &&
          Base64Decode(user, &key.first) && entry->GetString(kApp, &app) &&
          Base64Decode(app, &key.second) &&
          entry->GetInteger(kExpiration, &expiration)) {
        base::Time expiration_time = base::Time::FromTimeT(expiration);
        if (expiration_time > clock_->Now())
          entries_[key] = expiration_time;
      }
    }
    if (entries_.size() < list->GetSize()) {
      // Save some storage space by saving without expired entries.
      Save({});
    }
  }
}

void AccessBlackListManagerImpl::Save(const DoneCallback& callback) {
  if (!store_) {
    if (!callback.is_null())
      callback.Run(nullptr);
    return;
  }

  base::ListValue list;
  for (const auto& e : entries_) {
    scoped_ptr<base::DictionaryValue> entry{new base::DictionaryValue};
    entry->SetString(kUser, Base64Encode(e.first.first));
    entry->SetString(kApp, Base64Encode(e.first.second));
    entry->SetInteger(kExpiration, e.second.ToTimeT());
    list.Append(std::move(entry));
  }

  std::string json;
  base::JSONWriter::Write(list, &json);
  store_->SaveSettings(kConfigFileName, json, callback);
}

void AccessBlackListManagerImpl::RemoveExpired() {
  for (auto i = begin(entries_); i != end(entries_);) {
    if (i->second <= clock_->Now())
      i = entries_.erase(i);
    else
      ++i;
  }
}

void AccessBlackListManagerImpl::Block(const std::vector<uint8_t>& user_id,
                                       const std::vector<uint8_t>& app_id,
                                       const base::Time& expiration,
                                       const DoneCallback& callback) {
  // Iterating is OK as Save below is more expensive.
  RemoveExpired();
  if (expiration <= clock_->Now()) {
    if (!callback.is_null()) {
      ErrorPtr error;
      Error::AddTo(&error, FROM_HERE, "aleady_expired",
                   "Entry already expired");
      callback.Run(std::move(error));
    }
    return;
  }
  if (entries_.size() >= capacity_) {
    if (!callback.is_null()) {
      ErrorPtr error;
      Error::AddTo(&error, FROM_HERE, "blacklist_is_full",
                   "Unable to store more entries");
      callback.Run(std::move(error));
    }
    return;
  }
  auto& value = entries_[std::make_pair(user_id, app_id)];
  value = std::max(value, expiration);
  Save(callback);
}

void AccessBlackListManagerImpl::Unblock(const std::vector<uint8_t>& user_id,
                                         const std::vector<uint8_t>& app_id,
                                         const DoneCallback& callback) {
  if (!entries_.erase(std::make_pair(user_id, app_id))) {
    if (!callback.is_null()) {
      ErrorPtr error;
      Error::AddTo(&error, FROM_HERE, "entry_not_found", "Unknown entry");
      callback.Run(std::move(error));
    }
    return;
  }
  // Iterating is OK as Save below is more expensive.
  RemoveExpired();
  Save(callback);
}

bool AccessBlackListManagerImpl::IsBlocked(
    const std::vector<uint8_t>& user_id,
    const std::vector<uint8_t>& app_id) const {
  for (const auto& user : {{}, user_id}) {
    for (const auto& app : {{}, app_id}) {
      auto both = entries_.find(std::make_pair(user, app));
      if (both != end(entries_) && both->second > clock_->Now())
        return true;
    }
  }
  return false;
}

std::vector<AccessBlackListManager::Entry>
AccessBlackListManagerImpl::GetEntries() const {
  std::vector<Entry> result;
  for (const auto& e : entries_)
    result.push_back({e.first.first, e.first.second, e.second});
  return result;
}

size_t AccessBlackListManagerImpl::GetSize() const {
  return entries_.size();
}

size_t AccessBlackListManagerImpl::GetCapacity() const {
  return capacity_;
}

}  // namespace weave