• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "GdbConn"
16 #include "graph_connection.h"
17 
18 #include <unistd.h>
19 
20 #include <string>
21 #include <utility>
22 
23 #include "gdb_errors.h"
24 #include "gdb_utils.h"
25 #include "graph_statement.h"
26 #include "logger.h"
27 #include "rdb_security_manager.h"
28 #include "securec.h"
29 
30 namespace OHOS::DistributedDataAip {
31 __attribute__((used))
32 const int32_t GraphConnection::regCreator_ = Connection::RegisterCreator(DBType::DB_GRAPH, GraphConnection::Create);
33 
Create(const StoreConfig & config,bool isWriter)34 std::pair<int32_t, std::shared_ptr<Connection>> GraphConnection::Create(const StoreConfig &config, bool isWriter)
35 {
36     LOG_DEBUG("GraphConnection::Create start, name=%{public}s, isWriter=%{public}d",
37         GdbUtils::Anonymous(config.GetName()).c_str(), isWriter);
38     std::pair<int32_t, std::shared_ptr<Connection>> result = { E_INNER_ERROR, nullptr };
39     auto &[errCode, conn] = result;
40     for (size_t i = 0; i < ITERS_COUNT; i++) {
41         std::shared_ptr<GraphConnection> connection = std::make_shared<GraphConnection>(config, isWriter);
42         if (connection == nullptr) {
43             LOG_ERROR("Open new failed, connection is nullptr. name=%{public}s",
44                 GdbUtils::Anonymous(config.GetName()).c_str());
45             return result;
46         }
47         errCode = connection->InnerOpen(config);
48         if (errCode == E_OK) {
49             conn = connection;
50             break;
51         }
52         if (errCode == E_GRD_INVALID_ARGS && connection->IsEncryptInvalidChanged(config)) {
53             errCode = E_CONFIG_INVALID_CHANGE;
54             break;
55         }
56     }
57     return result;
58 }
59 
GraphConnection(const StoreConfig & config,bool isWriter)60 GraphConnection::GraphConnection(const StoreConfig &config, bool isWriter) : config_(config), isWriter_(isWriter)
61 {
62 }
63 
~GraphConnection()64 GraphConnection::~GraphConnection()
65 {
66     LOG_DEBUG("enter");
67     if (dbHandle_ != nullptr) {
68         int errCode = GrdAdapter::Close(dbHandle_, 0);
69         if (errCode != E_OK) {
70             LOG_ERROR("could not close database, err=%{public}d", errCode);
71         }
72         dbHandle_ = nullptr;
73     }
74 }
75 
InnerOpen(const StoreConfig & config)76 int GraphConnection::InnerOpen(const StoreConfig &config)
77 {
78     std::string dbPath = config.GetFullPath();
79     std::vector<uint8_t> newKey = config.GetNewEncryptKey();
80     if (!newKey.empty()) {
81         // NewKey exists, oldKey has expired, ResetKey is required
82         newKey.assign(newKey.size(), 0);
83         auto errCode = ResetKey(config);
84         if (errCode != E_OK) {
85             LOG_ERROR("Can not reset key %{public}d.", errCode);
86             return errCode;
87         }
88     }
89     std::vector<uint8_t> key = config.GetEncryptKey();
90     std::string configJson = GdbUtils::GetConfigStr(key, config.IsEncrypt());
91     LOG_DEBUG(
92         "GraphConnection::InnerOpen: dbPath=%{public}s, configJson=%{public}s",
93         GdbUtils::Anonymous(dbPath).c_str(), configJson.c_str());
94     int32_t errCode = GrdAdapter::Open(dbPath.c_str(), configJson.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_);
95     if (errCode == E_GRD_PASSWORD_NEED_REKEY) {
96         // Upgrading from non encrypted to encrypted, requires Rekey first and then Open
97         errCode = GrdAdapter::Rekey(dbPath.c_str(), GdbUtils::GetConfigStr({}, false).c_str(), key);
98         if (errCode != E_OK) {
99             key.assign(key.size(), 0);
100             GdbUtils::ClearAndZeroString(configJson);
101             LOG_ERROR("Can not rekey graph db %{public}d.", errCode);
102             return errCode;
103         }
104         errCode = GrdAdapter::Open(dbPath.c_str(), configJson.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_);
105     }
106     key.assign(key.size(), 0);
107     GdbUtils::ClearAndZeroString(configJson);
108     if (errCode != E_OK) {
109         LOG_ERROR("Can not open graph db, name=%{public}s, errCode=%{public}d.",
110             GdbUtils::Anonymous(config.GetName()).c_str(), errCode);
111         return errCode;
112     }
113     return errCode;
114 }
115 
CreateStatement(const std::string & gql,std::shared_ptr<Connection> connection)116 std::pair<int32_t, GraphConnection::Stmt> GraphConnection::CreateStatement(
117     const std::string &gql, std::shared_ptr<Connection> connection)
118 {
119     int32_t ret;
120     auto stmt = std::make_shared<GraphStatement>(dbHandle_, gql, connection, ret);
121     if (ret != E_OK) {
122         return { ret, nullptr };
123     }
124     return { ret, stmt };
125 }
126 
GetDBType() const127 DBType GraphConnection::GetDBType() const
128 {
129     return DBType::DB_GRAPH;
130 }
131 
IsWriter() const132 bool GraphConnection::IsWriter() const
133 {
134     return isWriter_;
135 }
136 
ResetKey(const StoreConfig & config)137 int32_t GraphConnection::ResetKey(const StoreConfig &config)
138 {
139     if (!IsWriter()) {
140         return E_OK;
141     }
142     std::string dbPath = config.GetFullPath();
143     std::vector<uint8_t> key = config.GetEncryptKey();
144     std::vector<uint8_t> newKey = config.GetNewEncryptKey();
145     std::string configStr = GdbUtils::GetConfigStr(key, config.IsEncrypt());
146     auto errCode = GrdAdapter::Rekey(dbPath.c_str(), configStr.c_str(), newKey);
147     GdbUtils::ClearAndZeroString(configStr);
148     key.assign(key.size(), 0);
149     newKey.assign(newKey.size(), 0);
150     if (errCode != E_OK) {
151         LOG_ERROR("Rekey failed, err = %{public}d, errno = %{public}d", errCode, errno);
152         NativeRdb::RdbSecurityManager::GetInstance().DelKeyFile(
153             config.GetFullPath(), NativeRdb::RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY);
154         return errCode;
155     }
156     config.ChangeEncryptKey();
157     return E_OK;
158 }
159 
IsEncryptInvalidChanged(const StoreConfig & config)160 bool GraphConnection::IsEncryptInvalidChanged(const StoreConfig &config)
161 {
162     if (config.GetFullPath().empty() || config.IsEncrypt()) {
163         LOG_WARN("Config has no path or config is encrypted, path: %{public}s, isEncrypt: %{public}d",
164             GdbUtils::Anonymous(config.GetFullPath()).c_str(), config.IsEncrypt());
165         return false;
166     }
167     return NativeRdb::RdbSecurityManager::GetInstance().IsKeyFileExists(config.GetFullPath(),
168         NativeRdb::RdbSecurityManager::KeyFileType::PUB_KEY_FILE);
169 }
170 } // namespace OHOS::DistributedDataAip
171