blob: 5c9cd237adecaa39125dd30afc39732203b9eb9b [file] [log] [blame]
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California
4 *
5 * This file is part of ndn-group-encrypt (Group-based Encryption Protocol for NDN).
6 * See AUTHORS.md for complete list of ndn-group-encrypt authors and contributors.
7 *
8 * ndn-group-encrypt is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndn-group-encrypt is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndn-group-encrypt, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
20 */
21
22#include "group-manager-db.hpp"
Zhiyi Zhang84986cc2015-09-21 00:26:07 +080023#include "algo/rsa.hpp"
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070024
25#include <sqlite3.h>
26#include <boost/filesystem.hpp>
27#include <ndn-cxx/util/sqlite3-statement.hpp>
28#include <ndn-cxx/security/identity-certificate.hpp>
29
30namespace ndn {
31namespace gep {
32
33using util::Sqlite3Statement;
34
35static const std::string INITIALIZATION =
36 "CREATE TABLE IF NOT EXISTS \n"
37 " schedules( \n"
38 " schedule_id INTEGER PRIMARY KEY, \n"
39 " schedule_name TEXT NOT NULL, \n"
40 " schedule BLOB NOT NULL \n"
41 " ); \n"
42 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
43 " scheduleNameIndex ON schedules(schedule_name); \n"
44 " \n"
45 "CREATE TABLE IF NOT EXISTS \n"
46 " members( \n"
47 " member_id INTEGER PRIMARY KEY, \n"
48 " schedule_id INTEGER NOT NULL, \n"
49 " member_name BLOB NOT NULL, \n"
Zhiyi Zhang84986cc2015-09-21 00:26:07 +080050 " key_name BLOB NOT NULL, \n"
51 " pubkey BLOB NOT NULL, \n"
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070052 " FOREIGN KEY(schedule_id) \n"
53 " REFERENCES schedules(schedule_id) \n"
54 " ON DELETE CASCADE \n"
55 " ON UPDATE CASCADE \n"
56 " ); \n"
57 "CREATE UNIQUE INDEX IF NOT EXISTS \n"
58 " memNameIndex ON members(member_name); \n";
59
60class GroupManagerDB::Impl
61{
62public:
Yingdi Yu8c43fcc2016-03-09 18:23:57 -080063 Impl(const std::string& dbPath)
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070064 {
65 // open Database
66
Yingdi Yu8c43fcc2016-03-09 18:23:57 -080067 int result = sqlite3_open_v2(dbPath.c_str(), &m_database,
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070068 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
69#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
70 "unix-dotfile"
71#else
72 nullptr
73#endif
74 );
75
76 if (result != SQLITE_OK)
Yingdi Yu8c43fcc2016-03-09 18:23:57 -080077 BOOST_THROW_EXCEPTION(Error("GroupManager DB cannot be opened/created: " + dbPath));
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -070078
79 // enable foreign key
80 sqlite3_exec(m_database, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr);
81
82 // initialize database specific tables
83 char* errorMessage = nullptr;
84 result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage);
85 if (result != SQLITE_OK && errorMessage != nullptr) {
86 sqlite3_free(errorMessage);
87 BOOST_THROW_EXCEPTION(Error("GroupManager DB cannot be initialized"));
88 }
89 }
90
91 ~Impl()
92 {
93 sqlite3_close(m_database);
94 }
95
96 int
97 getScheduleId(const std::string& name) const
98 {
99 Sqlite3Statement statement(m_database,
100 "SELECT schedule_id FROM schedules WHERE schedule_name=?");
101 statement.bind(1, name, SQLITE_TRANSIENT);
102
103 int result = -1;
104 if (statement.step() == SQLITE_ROW)
105 result = statement.getInt(0);
106 return result;
107 }
108
109public:
110 sqlite3* m_database;
111};
112
Yingdi Yu8c43fcc2016-03-09 18:23:57 -0800113GroupManagerDB::GroupManagerDB(const std::string& dbPath)
114 : m_impl(new Impl(dbPath))
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700115{
116}
117
118GroupManagerDB::~GroupManagerDB() = default;
119
120bool
121GroupManagerDB::hasSchedule(const std::string& name) const
122{
123 Sqlite3Statement statement(m_impl->m_database,
124 "SELECT schedule_id FROM schedules where schedule_name=?");
125 statement.bind(1, name, SQLITE_TRANSIENT);
126 return (statement.step() == SQLITE_ROW);
127}
128
129std::list<std::string>
130GroupManagerDB::listAllScheduleNames() const
131{
132 std::list<std::string> result;
133 Sqlite3Statement statement(m_impl->m_database,
134 "SELECT schedule_name FROM schedules");
135
136 result.clear();
137 while (statement.step() == SQLITE_ROW) {
138 result.push_back(statement.getString(0));
139 }
140 return result;
141}
142
143Schedule
144GroupManagerDB::getSchedule(const std::string& name) const
145{
146 Sqlite3Statement statement(m_impl->m_database,
147 "SELECT schedule FROM schedules where schedule_name=?");
148 statement.bind(1, name, SQLITE_TRANSIENT);
149
150 Schedule result;
151 if (statement.step() == SQLITE_ROW) {
152 result.wireDecode(statement.getBlock(0));
153 }
154 else {
155 BOOST_THROW_EXCEPTION(Error("Cannot get the result from database"));
156 }
157 return result;
158}
159
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800160std::map<Name, Buffer>
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700161GroupManagerDB::getScheduleMembers(const std::string& name) const
162{
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800163 std::map<Name, Buffer> result;
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700164 Sqlite3Statement statement(m_impl->m_database,
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800165 "SELECT key_name, pubkey\
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700166 FROM members JOIN schedules\
167 ON members.schedule_id=schedules.schedule_id\
168 WHERE schedule_name=?");
169 statement.bind(1, name, SQLITE_TRANSIENT);
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700170 result.clear();
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800171
172 const uint8_t* keyBytes = nullptr;
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700173 while (statement.step() == SQLITE_ROW) {
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800174 keyBytes = statement.getBlob(1);
175 const int& keyBytesSize = statement.getSize(1);
176 result.insert(std::pair<Name, Buffer>(Name(statement.getBlock(0)),
177 Buffer(keyBytes, keyBytesSize)));
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700178 }
179 return result;
180}
181
182void
183GroupManagerDB::addSchedule(const std::string& name, const Schedule& schedule)
184{
185 BOOST_ASSERT(name.length() != 0);
186
187 Sqlite3Statement statement(m_impl->m_database,
188 "INSERT INTO schedules (schedule_name, schedule)\
189 values (?, ?)");
190 statement.bind(1, name, SQLITE_TRANSIENT);
191 statement.bind(2, schedule.wireEncode(), SQLITE_TRANSIENT);
192 if (statement.step() != SQLITE_DONE)
193 BOOST_THROW_EXCEPTION(Error("Cannot add the schedule to database"));
194}
195
196void
197GroupManagerDB::deleteSchedule(const std::string& name)
198{
199 Sqlite3Statement statement(m_impl->m_database,
200 "DELETE FROM schedules WHERE schedule_name=?");
201 statement.bind(1, name, SQLITE_TRANSIENT);
202 statement.step();
203}
204
205void
206GroupManagerDB::renameSchedule(const std::string& oldName, const std::string& newName)
207{
208 BOOST_ASSERT(newName.length() != 0);
209
210 Sqlite3Statement statement(m_impl->m_database,
211 "UPDATE schedules SET schedule_name=? WHERE schedule_name=?");
212 statement.bind(1, newName, SQLITE_TRANSIENT);
213 statement.bind(2, oldName, SQLITE_TRANSIENT);
214 if (statement.step() != SQLITE_DONE)
215 BOOST_THROW_EXCEPTION(Error("Cannot rename the schedule from database"));
216}
217
218void
219GroupManagerDB::updateSchedule(const std::string& name, const Schedule& schedule)
220{
221 if (!hasSchedule(name)) {
222 addSchedule(name, schedule);
223 return;
224 }
225
226 Sqlite3Statement statement(m_impl->m_database,
227 "UPDATE schedules SET schedule=? WHERE schedule_name=?");
228 statement.bind(1, schedule.wireEncode(), SQLITE_TRANSIENT);
229 statement.bind(2, name, SQLITE_TRANSIENT);
230 statement.step();
231}
232
233bool
234GroupManagerDB::hasMember(const Name& identity) const
235{
236 Sqlite3Statement statement(m_impl->m_database,
237 "SELECT member_id FROM members WHERE member_name=?");
238 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
239 return (statement.step() == SQLITE_ROW);
240}
241
242std::list<Name>
243GroupManagerDB::listAllMembers() const
244{
245 std::list<Name> result;
246 Sqlite3Statement statement(m_impl->m_database,
247 "SELECT member_name FROM members");
248
249 result.clear();
250 while (statement.step() == SQLITE_ROW) {
251 result.push_back(Name(statement.getBlock(0)));
252 }
253 return result;
254}
255
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700256std::string
257GroupManagerDB::getMemberSchedule(const Name& identity) const
258{
259 Sqlite3Statement statement(m_impl->m_database,
260 "SELECT schedule_name\
261 FROM schedules JOIN members\
262 ON schedules.schedule_id = members.schedule_id\
263 WHERE member_name=?");
264 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
265
266 std::string result = "";
267 if (statement.step() == SQLITE_ROW) {
268 result = statement.getString(0);
269 }
270 else {
271 BOOST_THROW_EXCEPTION(Error("Cannot get the result from database"));
272 }
273 return result;
274}
275
276void
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800277GroupManagerDB::addMember(const std::string& scheduleName, const Name& keyName,
278 const Buffer& key)
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700279{
280 int scheduleId = m_impl->getScheduleId(scheduleName);
281 if (scheduleId == -1)
282 BOOST_THROW_EXCEPTION(Error("The schedule dose not exist"));
283
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800284 // need to be changed in the future
285 Name memberName = keyName.getPrefix(-1);
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700286
287 Sqlite3Statement statement(m_impl->m_database,
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800288 "INSERT INTO members(schedule_id, member_name, key_name, pubkey)\
289 values (?, ?, ?, ?)");
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700290 statement.bind(1, scheduleId);
291 statement.bind(2, memberName.wireEncode(), SQLITE_TRANSIENT);
Zhiyi Zhang84986cc2015-09-21 00:26:07 +0800292 statement.bind(3, keyName.wireEncode(), SQLITE_TRANSIENT);
293 statement.bind(4, key.buf(), key.size(), SQLITE_TRANSIENT);
294
Zhiyi Zhang7cc09fc2015-09-01 13:40:32 -0700295 if (statement.step() != SQLITE_DONE)
296 BOOST_THROW_EXCEPTION(Error("Cannot add the member to database"));
297}
298
299void
300GroupManagerDB::updateMemberSchedule(const Name& identity, const std::string& scheduleName)
301{
302 int scheduleId = m_impl->getScheduleId(scheduleName);
303 if (scheduleId == -1)
304 BOOST_THROW_EXCEPTION(Error("The schedule dose not exist"));
305
306 Sqlite3Statement statement(m_impl->m_database,
307 "UPDATE members SET schedule_id=? WHERE member_name=?");
308 statement.bind(1, scheduleId);
309 statement.bind(2, identity.wireEncode(), SQLITE_TRANSIENT);
310 statement.step();
311}
312
313void
314GroupManagerDB::deleteMember(const Name& identity)
315{
316 Sqlite3Statement statement(m_impl->m_database,
317 "DELETE FROM members WHERE member_name=?");
318 statement.bind(1, identity.wireEncode(), SQLITE_TRANSIENT);
319 statement.step();
320}
321
322} // namespace gep
323} // namespace ndn