1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <filesystem>
17#include <system_error>
18
19#include "hilog/log.h"
20#include "netmgr_ext_log_wrapper.h"
21#include "netfirewall_database.h"
22
23using namespace OHOS::NativeRdb;
24
25namespace OHOS {
26namespace NetManagerStandard {
27std::shared_ptr<NetFirewallDataBase> NetFirewallDataBase::instance_ = nullptr;
28
29NetFirewallDataBase::NetFirewallDataBase()
30{
31    if (!std::filesystem::exists(FIREWALL_DB_PATH)) {
32        std::error_code ec;
33        if (std::filesystem::create_directories(FIREWALL_DB_PATH, ec)) {
34            NETMGR_EXT_LOG_D("create_directories success :%{public}s", FIREWALL_DB_PATH.c_str());
35        } else {
36            NETMGR_EXT_LOG_E("create_directories error :%{public}s : %s", FIREWALL_DB_PATH.c_str(),
37                ec.message().c_str());
38        }
39    }
40    std::string firewallDatabaseName = FIREWALL_DB_PATH + FIREWALL_DB_NAME;
41    int32_t errCode = OHOS::NativeRdb::E_OK;
42    OHOS::NativeRdb::RdbStoreConfig config(firewallDatabaseName);
43    config.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
44    NetFirewallDataBaseCallBack sqliteOpenHelperCallback;
45    store_ = OHOS::NativeRdb::RdbHelper::GetRdbStore(config, DATABASE_OPEN_VERSION, sqliteOpenHelperCallback, errCode);
46    if (errCode == OHOS::NativeRdb::E_SQLITE_CORRUPT) {
47        if (!RestoreDatabaseWhenInit()) {
48            NETMGR_EXT_LOG_E("Create and restore db error");
49            return;
50        }
51        NETMGR_EXT_LOG_I("Create db error, restore db success");
52        errCode = OHOS::NativeRdb::E_OK;
53    }
54    if (errCode != OHOS::NativeRdb::E_OK) {
55        NETMGR_EXT_LOG_E("GetRdbStore errCode :%{public}d", errCode);
56    } else {
57        NETMGR_EXT_LOG_D("GetRdbStore success :%{public}d", errCode);
58    }
59}
60
61std::shared_ptr<NetFirewallDataBase> NetFirewallDataBase::GetInstance()
62{
63    if (instance_ == nullptr) {
64        NETMGR_EXT_LOG_W("reset to new instance");
65        instance_.reset(new NetFirewallDataBase());
66        return instance_;
67    }
68    return instance_;
69}
70
71int32_t NetFirewallDataBase::BeginTransaction()
72{
73    if (store_ == nullptr) {
74        NETMGR_EXT_LOG_E("BeginTransaction store_ is nullptr");
75        return FIREWALL_RDB_NO_INIT;
76    }
77    int32_t ret = store_->BeginTransaction();
78    if (ret != OHOS::NativeRdb::E_OK) {
79        NETMGR_EXT_LOG_E("BeginTransaction fail :%{public}d", ret);
80        return FIREWALL_RDB_EXECUTE_FAILTURE;
81    }
82    return FIREWALL_OK;
83}
84
85int32_t NetFirewallDataBase::Commit()
86{
87    if (store_ == nullptr) {
88        NETMGR_EXT_LOG_E("Commit store_ is nullptr");
89        return FIREWALL_RDB_NO_INIT;
90    }
91    int32_t ret = store_->Commit();
92    if (ret != OHOS::NativeRdb::E_OK) {
93        NETMGR_EXT_LOG_E("Commit fail :%{public}d", ret);
94        return FIREWALL_RDB_EXECUTE_FAILTURE;
95    }
96    return FIREWALL_OK;
97}
98
99int32_t NetFirewallDataBase::RollBack()
100{
101    if (store_ == nullptr) {
102        NETMGR_EXT_LOG_E("RollBack store_ is nullptr");
103        return FIREWALL_RDB_NO_INIT;
104    }
105    int32_t ret = store_->RollBack();
106    if (ret != OHOS::NativeRdb::E_OK) {
107        NETMGR_EXT_LOG_E("RollBack fail :%{public}d", ret);
108        return FIREWALL_RDB_EXECUTE_FAILTURE;
109    }
110    return FIREWALL_OK;
111}
112
113int64_t NetFirewallDataBase::Insert(const OHOS::NativeRdb::ValuesBucket &insertValues, const std::string tableName)
114{
115    if (store_ == nullptr) {
116        NETMGR_EXT_LOG_E("Insert store_ is  nullptr");
117        return FIREWALL_RDB_NO_INIT;
118    }
119    int64_t outRowId = 0;
120    int32_t ret = store_->Insert(outRowId, tableName, insertValues);
121    NETMGR_EXT_LOG_D("Insert id=%{public}" PRIu64 "", outRowId);
122    if (ret == OHOS::NativeRdb::E_SQLITE_CORRUPT) {
123        NETMGR_EXT_LOG_E("Insert error, restore db");
124        if (RestoreDatabase()) {
125            int32_t ret = store_->Insert(outRowId, tableName, insertValues);
126        }
127    }
128    if (ret != OHOS::NativeRdb::E_OK) {
129        NETMGR_EXT_LOG_E("Insert ret :%{public}d", ret);
130        return FIREWALL_RDB_EXECUTE_FAILTURE;
131    }
132    if (tableName == FIREWALL_TABLE_NAME) {
133        BackupDatebase();
134    }
135    return outRowId;
136}
137
138
139int32_t NetFirewallDataBase::Update(const std::string &tableName, int32_t &changedRows,
140    const OHOS::NativeRdb::ValuesBucket &values, const std::string &whereClause,
141    const std::vector<std::string> &whereArgs)
142{
143    if (store_ == nullptr) {
144        NETMGR_EXT_LOG_E("Update(whereClause) store_ is nullptr");
145        return FIREWALL_RDB_NO_INIT;
146    }
147    int32_t ret = store_->Update(changedRows, tableName, values, whereClause, whereArgs);
148    if (ret == OHOS::NativeRdb::E_SQLITE_CORRUPT) {
149        NETMGR_EXT_LOG_E("Update error, restore db");
150        if (RestoreDatabase()) {
151            int32_t ret = store_->Update(changedRows, tableName, values, whereClause, whereArgs);
152        }
153    }
154    if (ret != OHOS::NativeRdb::E_OK) {
155        NETMGR_EXT_LOG_E("Update(whereClause) ret :%{public}d", ret);
156        return FIREWALL_RDB_EXECUTE_FAILTURE;
157    }
158    if (tableName == FIREWALL_TABLE_NAME) {
159        BackupDatebase();
160    }
161    return FIREWALL_OK;
162}
163
164
165int32_t NetFirewallDataBase::Delete(const std::string &tableName, int32_t &changedRows, const std::string &whereClause,
166    const std::vector<std::string> &whereArgs)
167{
168    if (store_ == nullptr) {
169        NETMGR_EXT_LOG_E("Delete store_ is nullptr");
170        return FIREWALL_RDB_NO_INIT;
171    }
172    int32_t ret = store_->Delete(changedRows, tableName, whereClause, whereArgs);
173    if (ret == OHOS::NativeRdb::E_SQLITE_CORRUPT) {
174        NETMGR_EXT_LOG_E("Delete error, restore db");
175        if (RestoreDatabase()) {
176            int32_t ret = store_->Delete(changedRows, tableName, whereClause, whereArgs);
177        }
178    }
179    if (ret != OHOS::NativeRdb::E_OK) {
180        NETMGR_EXT_LOG_E("Delete(whereClause) ret :%{public}d", ret);
181        return FIREWALL_RDB_EXECUTE_FAILTURE;
182    }
183    if (tableName == FIREWALL_TABLE_NAME) {
184        BackupDatebase();
185    }
186    return FIREWALL_OK;
187}
188
189
190std::shared_ptr<OHOS::NativeRdb::ResultSet> NetFirewallDataBase::Query(
191    const OHOS::NativeRdb::AbsRdbPredicates &predicates, const std::vector<std::string> &columns)
192{
193    if (store_ == nullptr) {
194        NETMGR_EXT_LOG_E("Query(AbsRdbPredicates) store_ is nullptr");
195        return nullptr;
196    }
197    return store_->Query(predicates, columns);
198}
199
200int32_t NetFirewallDataBase::Count(int64_t &outValue, const OHOS::NativeRdb::AbsRdbPredicates &predicates)
201{
202    if (store_ == nullptr) {
203        NETMGR_EXT_LOG_E("Count(AbsRdbPredicates) store_ is nullptr");
204        return FIREWALL_RDB_NO_INIT;
205    }
206    return store_->Count(outValue, predicates);
207}
208
209std::shared_ptr<OHOS::NativeRdb::ResultSet> NetFirewallDataBase::QuerySql(const std::string &sql,
210    const std::vector<std::string> &selectionArgs)
211{
212    if (store_ == nullptr) {
213        NETMGR_EXT_LOG_E("QuerySql(AbsRdbPredicates) store_ is nullptr");
214        return nullptr;
215    }
216    return store_->QuerySql(sql, selectionArgs);
217}
218
219void NetFirewallDataBase::BackupDatebase()
220{
221    if (store_ == nullptr) {
222        NETMGR_EXT_LOG_E("store_ is null");
223        return;
224    }
225
226    if (backing_.exchange(true)) {
227        NETMGR_EXT_LOG_I("Backup is processing");
228        return;
229    }
230    std::string fileName = FIREWALL_DB_PATH + FIREWALL_BACKUP_DB_NAME;
231    std::thread thread([fileName, rdbStore = store_] {
232        auto errCode = rdbStore->Backup(fileName);
233        NetFirewallDataBase::GetInstance()->backing_ = false;
234        if (errCode != E_OK) {
235            NETMGR_EXT_LOG_E("Backup Datebase error");
236            return;
237        }
238        NETMGR_EXT_LOG_D("Backup Datebase success");
239    });
240    thread.detach();
241}
242
243bool NetFirewallDataBase::RestoreDatabaseWhenInit()
244{
245    std::string backupFile = FIREWALL_DB_PATH + FIREWALL_BACKUP_DB_NAME;
246    if (access(backupFile.c_str(), F_OK) != 0) {
247        NETMGR_EXT_LOG_I("Backup db is not exist");
248        return false;
249    }
250    std::string firewallFile = FIREWALL_DB_PATH + FIREWALL_DB_NAME;
251    if (rename(backupFile.c_str(), firewallFile.c_str()) != 0) {
252        return false;
253    }
254    int32_t errCode = OHOS::NativeRdb::E_OK;
255    OHOS::NativeRdb::RdbStoreConfig config(firewallFile);
256    config.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
257    NetFirewallDataBaseCallBack sqliteOpenHelperCallback;
258    store_ = OHOS::NativeRdb::RdbHelper::GetRdbStore(config, DATABASE_OPEN_VERSION, sqliteOpenHelperCallback, errCode);
259    if (errCode != OHOS::NativeRdb::E_OK) {
260        NETMGR_EXT_LOG_E("Restore GetRdbStore errCode :%{public}d", errCode);
261        return false;
262    } else {
263        NETMGR_EXT_LOG_D("Restore GetRdbStore success");
264    }
265    return true;
266}
267
268bool NetFirewallDataBase::RestoreDatabase()
269{
270    if (store_ == nullptr) {
271        NETMGR_EXT_LOG_E("store_ is null");
272        return false;
273    }
274    auto fileName = FIREWALL_DB_PATH + FIREWALL_BACKUP_DB_NAME;
275    if (access(fileName.c_str(), F_OK) != 0) {
276        NETMGR_EXT_LOG_I("Backup db is not exist");
277        return false;
278    }
279    int32_t errCode = store_->Restore(fileName);
280    if (errCode == E_OK) {
281        NETMGR_EXT_LOG_I("Restore db success");
282        return true;
283    }
284
285    // Failed to restore the db. Try to rebuild the db from the backup db.
286    store_ = nullptr;
287    return RestoreDatabaseWhenInit();
288}
289
290int32_t NetFirewallDataBaseCallBack::OnCreate(OHOS::NativeRdb::RdbStore &store)
291{
292    std::map<std::string, std::string> netfirewallTableMap;
293    netfirewallTableMap.insert(std::pair<std::string, std::string>(FIREWALL_TABLE_NAME, CREATE_FIREWALL_TABLE));
294    netfirewallTableMap.insert(std::pair<std::string, std::string>(INTERCEPT_RECORD_TABLE, CREATE_RECORD_TABLE));
295    for (const auto &pair : netfirewallTableMap) {
296        std::string sql = pair.second;
297        int32_t ret = store.ExecuteSql(sql);
298        if (ret != OHOS::NativeRdb::E_OK) {
299            NETMGR_EXT_LOG_E("OnCreate %{public}s, failed: %{public}d", pair.first.c_str(), ret);
300            return FIREWALL_RDB_EXECUTE_FAILTURE;
301        }
302        NETMGR_EXT_LOG_D("DB OnCreate Done %{public}s ", pair.first.c_str());
303    }
304    return FIREWALL_OK;
305}
306
307int32_t NetFirewallDataBaseCallBack::OnUpgrade(OHOS::NativeRdb::RdbStore &store, int32_t oldVersion, int32_t newVersion)
308{
309    NETMGR_EXT_LOG_D("DB OnUpgrade Enter");
310    (void)store;
311    (void)oldVersion;
312    (void)newVersion;
313    return FIREWALL_OK;
314}
315
316int32_t NetFirewallDataBaseCallBack::OnDowngrade(OHOS::NativeRdb::RdbStore &store, int32_t oldVersion,
317    int32_t newVersion)
318{
319    NETMGR_EXT_LOG_D("DB OnDowngrade Enter");
320    (void)store;
321    (void)oldVersion;
322    (void)newVersion;
323    return FIREWALL_OK;
324}
325} // namespace NetManagerStandard
326} // namespace OHOS