153c3577eSopenharmony_ci/*
253c3577eSopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
353c3577eSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
453c3577eSopenharmony_ci * you may not use this file except in compliance with the License.
553c3577eSopenharmony_ci * You may obtain a copy of the License at
653c3577eSopenharmony_ci *
753c3577eSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
853c3577eSopenharmony_ci *
953c3577eSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1053c3577eSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1153c3577eSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1253c3577eSopenharmony_ci * See the License for the specific language governing permissions and
1353c3577eSopenharmony_ci * limitations under the License.
1453c3577eSopenharmony_ci */
1553c3577eSopenharmony_ci#define LOG_TAG "Upgrade"
1653c3577eSopenharmony_ci#include "upgrade.h"
1753c3577eSopenharmony_ci
1853c3577eSopenharmony_ci#include <chrono>
1953c3577eSopenharmony_ci#include <cinttypes>
2053c3577eSopenharmony_ci
2153c3577eSopenharmony_ci#include "accesstoken_kit.h"
2253c3577eSopenharmony_ci#include "crypto_manager.h"
2353c3577eSopenharmony_ci#include "device_manager_adapter.h"
2453c3577eSopenharmony_ci#include "directory/directory_manager.h"
2553c3577eSopenharmony_ci#include "kvdb_general_store.h"
2653c3577eSopenharmony_ci#include "log_print.h"
2753c3577eSopenharmony_ci#include "metadata/meta_data_manager.h"
2853c3577eSopenharmony_ci#include "metadata/secret_key_meta_data.h"
2953c3577eSopenharmony_cinamespace OHOS::DistributedKv {
3053c3577eSopenharmony_ciusing namespace OHOS::DistributedData;
3153c3577eSopenharmony_ciusing system_clock = std::chrono::system_clock;
3253c3577eSopenharmony_ciusing DMAdapter = DistributedData::DeviceManagerAdapter;
3353c3577eSopenharmony_ciusing DBKey = DistributedDB::Key;
3453c3577eSopenharmony_ci
3553c3577eSopenharmony_ciUpgrade &Upgrade::GetInstance()
3653c3577eSopenharmony_ci{
3753c3577eSopenharmony_ci    static Upgrade upgrade;
3853c3577eSopenharmony_ci    return upgrade;
3953c3577eSopenharmony_ci}
4053c3577eSopenharmony_ci
4153c3577eSopenharmony_ciUpgrade::DBStatus Upgrade::UpdateStore(const StoreMeta &old, const StoreMeta &meta, const std::vector<uint8_t> &pwd)
4253c3577eSopenharmony_ci{
4353c3577eSopenharmony_ci    if (old.version < StoreMeta::UUID_CHANGED_TAG && old.storeType == DEVICE_COLLABORATION) {
4453c3577eSopenharmony_ci        auto upStatus = Upgrade::GetInstance().UpdateUuid(old, meta, pwd);
4553c3577eSopenharmony_ci        if (upStatus != DBStatus::OK) {
4653c3577eSopenharmony_ci            return DBStatus::DB_ERROR;
4753c3577eSopenharmony_ci        }
4853c3577eSopenharmony_ci    }
4953c3577eSopenharmony_ci
5053c3577eSopenharmony_ci    if (old.dataDir == meta.dataDir) {
5153c3577eSopenharmony_ci        return DBStatus::OK;
5253c3577eSopenharmony_ci    }
5353c3577eSopenharmony_ci
5453c3577eSopenharmony_ci    if (!exporter_ || !cleaner_) {
5553c3577eSopenharmony_ci        return DBStatus::NOT_SUPPORT;
5653c3577eSopenharmony_ci    }
5753c3577eSopenharmony_ci
5853c3577eSopenharmony_ci    DBPassword password;
5953c3577eSopenharmony_ci    auto backupFile = exporter_(old, password);
6053c3577eSopenharmony_ci    if (backupFile.empty()) {
6153c3577eSopenharmony_ci        return DBStatus::NOT_FOUND;
6253c3577eSopenharmony_ci    }
6353c3577eSopenharmony_ci
6453c3577eSopenharmony_ci    auto kvStore = GetDBStore(meta, pwd);
6553c3577eSopenharmony_ci    if (kvStore == nullptr) {
6653c3577eSopenharmony_ci        return DBStatus::DB_ERROR;
6753c3577eSopenharmony_ci    }
6853c3577eSopenharmony_ci
6953c3577eSopenharmony_ci    cleaner_(old);
7053c3577eSopenharmony_ci    return DBStatus::OK;
7153c3577eSopenharmony_ci}
7253c3577eSopenharmony_ci
7353c3577eSopenharmony_ciUpgrade::DBStatus Upgrade::ExportStore(const StoreMeta &old, const StoreMeta &meta)
7453c3577eSopenharmony_ci{
7553c3577eSopenharmony_ci    if (old.dataDir == meta.dataDir) {
7653c3577eSopenharmony_ci        return DBStatus::OK;
7753c3577eSopenharmony_ci    }
7853c3577eSopenharmony_ci
7953c3577eSopenharmony_ci    if (!exporter_) {
8053c3577eSopenharmony_ci        return DBStatus::NOT_SUPPORT;
8153c3577eSopenharmony_ci    }
8253c3577eSopenharmony_ci
8353c3577eSopenharmony_ci    DBPassword password;
8453c3577eSopenharmony_ci    auto backupFile = exporter_(old, password);
8553c3577eSopenharmony_ci    if (backupFile.empty()) {
8653c3577eSopenharmony_ci        return DBStatus::NOT_FOUND;
8753c3577eSopenharmony_ci    }
8853c3577eSopenharmony_ci    return DBStatus::OK;
8953c3577eSopenharmony_ci}
9053c3577eSopenharmony_ci
9153c3577eSopenharmony_civoid Upgrade::UpdatePassword(const StoreMeta &meta, const std::vector<uint8_t> &password)
9253c3577eSopenharmony_ci{
9353c3577eSopenharmony_ci    if (!meta.isEncrypt) {
9453c3577eSopenharmony_ci        return;
9553c3577eSopenharmony_ci    }
9653c3577eSopenharmony_ci
9753c3577eSopenharmony_ci    SecretKeyMetaData secretKey;
9853c3577eSopenharmony_ci    secretKey.storeType = meta.storeType;
9953c3577eSopenharmony_ci    secretKey.sKey = CryptoManager::GetInstance().Encrypt(password);
10053c3577eSopenharmony_ci    auto time = system_clock::to_time_t(system_clock::now());
10153c3577eSopenharmony_ci    secretKey.time = { reinterpret_cast<uint8_t *>(&time), reinterpret_cast<uint8_t *>(&time) + sizeof(time) };
10253c3577eSopenharmony_ci    MetaDataManager::GetInstance().SaveMeta(meta.GetSecretKey(), secretKey, true);
10353c3577eSopenharmony_ci}
10453c3577eSopenharmony_ci
10553c3577eSopenharmony_ciUpgrade::DBStatus Upgrade::UpdateUuid(const StoreMeta &old, const StoreMeta &meta, const std::vector<uint8_t> &pwd)
10653c3577eSopenharmony_ci{
10753c3577eSopenharmony_ci    auto kvStore = GetDBStore(meta, pwd);
10853c3577eSopenharmony_ci    if (kvStore == nullptr) {
10953c3577eSopenharmony_ci        return DBStatus::DB_ERROR;
11053c3577eSopenharmony_ci    }
11153c3577eSopenharmony_ci    kvStore->RemoveDeviceData();
11253c3577eSopenharmony_ci    auto uuid = GetEncryptedUuidByMeta(meta);
11353c3577eSopenharmony_ci    auto dbStatus = kvStore->UpdateKey([uuid](const DBKey &originKey, DBKey &newKey) {
11453c3577eSopenharmony_ci        newKey = originKey;
11553c3577eSopenharmony_ci        errno_t err = EOK;
11653c3577eSopenharmony_ci        err = memcpy_s(newKey.data(), newKey.size(), uuid.data(), uuid.size());
11753c3577eSopenharmony_ci        if (err != EOK) {
11853c3577eSopenharmony_ci            ZLOGE("memcpy_s failed, err:%{public}d", err);
11953c3577eSopenharmony_ci        }
12053c3577eSopenharmony_ci    });
12153c3577eSopenharmony_ci    if (dbStatus != DBStatus::OK) {
12253c3577eSopenharmony_ci        ZLOGE("fail to update Uuid, status:%{public}d", dbStatus);
12353c3577eSopenharmony_ci    }
12453c3577eSopenharmony_ci    return dbStatus;
12553c3577eSopenharmony_ci}
12653c3577eSopenharmony_ci
12753c3577eSopenharmony_cibool Upgrade::RegisterExporter(uint32_t version, Exporter exporter)
12853c3577eSopenharmony_ci{
12953c3577eSopenharmony_ci    (void)version;
13053c3577eSopenharmony_ci    exporter_ = std::move(exporter);
13153c3577eSopenharmony_ci    return exporter_ != nullptr;
13253c3577eSopenharmony_ci}
13353c3577eSopenharmony_ci
13453c3577eSopenharmony_cibool Upgrade::RegisterCleaner(uint32_t version, Cleaner cleaner)
13553c3577eSopenharmony_ci{
13653c3577eSopenharmony_ci    (void)version;
13753c3577eSopenharmony_ci    cleaner_ = std::move(cleaner);
13853c3577eSopenharmony_ci    return cleaner_ != nullptr;
13953c3577eSopenharmony_ci}
14053c3577eSopenharmony_ci
14153c3577eSopenharmony_ciUpgrade::AutoStore Upgrade::GetDBStore(const StoreMeta &meta, const std::vector<uint8_t> &pwd)
14253c3577eSopenharmony_ci{
14353c3577eSopenharmony_ci    DBManager manager(meta.appId, meta.user, meta.instanceId);
14453c3577eSopenharmony_ci    manager.SetKvStoreConfig({ DirectoryManager::GetInstance().GetStorePath(meta) });
14553c3577eSopenharmony_ci    auto release = [&manager](DBStore *store) { manager.CloseKvStore(store); };
14653c3577eSopenharmony_ci    DBPassword password;
14753c3577eSopenharmony_ci    password.SetValue(pwd.data(), pwd.size());
14853c3577eSopenharmony_ci    AutoStore dbStore(nullptr, release);
14953c3577eSopenharmony_ci    manager.GetKvStore(meta.storeId, KVDBGeneralStore::GetDBOption(meta, password),
15053c3577eSopenharmony_ci        [&dbStore](auto dbStatus, auto *tmpStore) {
15153c3577eSopenharmony_ci            dbStore.reset(tmpStore);
15253c3577eSopenharmony_ci        });
15353c3577eSopenharmony_ci    return dbStore;
15453c3577eSopenharmony_ci}
15553c3577eSopenharmony_ci
15653c3577eSopenharmony_cistd::string Upgrade::GetEncryptedUuidByMeta(const StoreMeta &meta)
15753c3577eSopenharmony_ci{
15853c3577eSopenharmony_ci    std::string keyUuid = meta.appId + meta.deviceId;
15953c3577eSopenharmony_ci    auto pair = calcUuid_.Find(keyUuid);
16053c3577eSopenharmony_ci    if (pair.first) {
16153c3577eSopenharmony_ci        return pair.second;
16253c3577eSopenharmony_ci    }
16353c3577eSopenharmony_ci    std::string uuid;
16453c3577eSopenharmony_ci    if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(meta.tokenId) ==
16553c3577eSopenharmony_ci        OHOS::Security::AccessToken::TOKEN_HAP) {
16653c3577eSopenharmony_ci        uuid = DMAdapter::GetInstance().CalcClientUuid(meta.appId, meta.deviceId);
16753c3577eSopenharmony_ci        calcUuid_.Insert(keyUuid, uuid);
16853c3577eSopenharmony_ci        return uuid;
16953c3577eSopenharmony_ci    }
17053c3577eSopenharmony_ci    uuid = DMAdapter::GetInstance().CalcClientUuid(" ", meta.deviceId);
17153c3577eSopenharmony_ci    calcUuid_.Insert(keyUuid, uuid);
17253c3577eSopenharmony_ci    return uuid;
17353c3577eSopenharmony_ci}
17453c3577eSopenharmony_ci} // namespace OHOS::DistributedKv