libcouchbase 1.2.8 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -4
  3. data/README.md +16 -8
  4. data/ext/libcouchbase/CMakeLists.txt +34 -32
  5. data/ext/libcouchbase/RELEASE_NOTES.markdown +277 -6
  6. data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +14 -0
  7. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibevent.cmake +2 -0
  8. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibuv.cmake +2 -1
  9. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
  10. data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +8 -1
  11. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  12. data/ext/libcouchbase/cmake/config-cmake.h.in +14 -0
  13. data/ext/libcouchbase/cmake/configure +8 -26
  14. data/ext/libcouchbase/cmake/defs.mk.in +2 -2
  15. data/ext/libcouchbase/cmake/libcouchbase.stp.in +829 -0
  16. data/ext/libcouchbase/cmake/source_files.cmake +11 -2
  17. data/ext/libcouchbase/contrib/cbsasl/CMakeLists.txt +18 -2
  18. data/ext/libcouchbase/contrib/cbsasl/include/cbsasl/cbsasl.h +44 -2
  19. data/ext/libcouchbase/contrib/cbsasl/src/client.c +285 -73
  20. data/ext/libcouchbase/contrib/cbsasl/src/common.c +4 -0
  21. data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.c +500 -0
  22. data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.h +99 -0
  23. data/ext/libcouchbase/contrib/cliopts/CMakeLists.txt +1 -1
  24. data/ext/libcouchbase/contrib/cliopts/cliopts.h +14 -1
  25. data/ext/libcouchbase/contrib/snappy/CMakeLists.txt +2 -3
  26. data/ext/libcouchbase/contrib/snappy/snappy-sinksource.cc +4 -0
  27. data/ext/libcouchbase/contrib/snappy/snappy-stubs-public.h +7 -5
  28. data/ext/libcouchbase/contrib/snappy/snappy.cc +7 -2
  29. data/ext/libcouchbase/example/crypto/.gitignore +2 -0
  30. data/ext/libcouchbase/example/crypto/Makefile +13 -0
  31. data/ext/libcouchbase/example/crypto/common_provider.c +24 -0
  32. data/ext/libcouchbase/example/crypto/common_provider.h +31 -0
  33. data/ext/libcouchbase/example/crypto/openssl_symmetric_decrypt.c +139 -0
  34. data/ext/libcouchbase/example/crypto/openssl_symmetric_encrypt.c +147 -0
  35. data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.c +281 -0
  36. data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.h +29 -0
  37. data/ext/libcouchbase/example/tracing/.gitignore +2 -0
  38. data/ext/libcouchbase/example/tracing/Makefile +8 -0
  39. data/ext/libcouchbase/example/tracing/cJSON.c +1 -0
  40. data/ext/libcouchbase/example/tracing/cJSON.h +1 -0
  41. data/ext/libcouchbase/example/tracing/tracing.c +439 -0
  42. data/ext/libcouchbase/example/tracing/views.c +444 -0
  43. data/ext/libcouchbase/include/libcouchbase/auth.h +56 -4
  44. data/ext/libcouchbase/include/libcouchbase/cbft.h +8 -0
  45. data/ext/libcouchbase/include/libcouchbase/cntl-private.h +55 -1
  46. data/ext/libcouchbase/include/libcouchbase/cntl.h +101 -1
  47. data/ext/libcouchbase/include/libcouchbase/configuration.h.in +6 -0
  48. data/ext/libcouchbase/include/libcouchbase/couchbase.h +109 -6
  49. data/ext/libcouchbase/include/libcouchbase/crypto.h +140 -0
  50. data/ext/libcouchbase/include/libcouchbase/error.h +38 -2
  51. data/ext/libcouchbase/include/libcouchbase/kvbuf.h +6 -1
  52. data/ext/libcouchbase/include/libcouchbase/metrics.h +79 -0
  53. data/ext/libcouchbase/include/libcouchbase/n1ql.h +9 -0
  54. data/ext/libcouchbase/include/libcouchbase/tracing.h +319 -0
  55. data/ext/libcouchbase/include/libcouchbase/vbucket.h +1 -1
  56. data/ext/libcouchbase/include/libcouchbase/views.h +8 -0
  57. data/ext/libcouchbase/include/memcached/protocol_binary.h +40 -10
  58. data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +6 -14
  59. data/ext/libcouchbase/plugins/io/libuv/plugin-internal.h +3 -0
  60. data/ext/libcouchbase/plugins/io/libuv/plugin-libuv.c +1 -0
  61. data/ext/libcouchbase/plugins/io/select/plugin-select.c +4 -1
  62. data/ext/libcouchbase/src/auth-priv.h +36 -4
  63. data/ext/libcouchbase/src/auth.cc +66 -27
  64. data/ext/libcouchbase/src/bootstrap.cc +1 -1
  65. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +12 -7
  66. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +26 -17
  67. data/ext/libcouchbase/src/bucketconfig/bc_http.h +1 -1
  68. data/ext/libcouchbase/src/bucketconfig/clconfig.h +4 -2
  69. data/ext/libcouchbase/src/bucketconfig/confmon.cc +6 -3
  70. data/ext/libcouchbase/src/cbft.cc +48 -0
  71. data/ext/libcouchbase/src/cntl.cc +138 -2
  72. data/ext/libcouchbase/src/config_static.h +17 -0
  73. data/ext/libcouchbase/src/connspec.cc +54 -6
  74. data/ext/libcouchbase/src/connspec.h +9 -1
  75. data/ext/libcouchbase/src/crypto.cc +386 -0
  76. data/ext/libcouchbase/src/ctx-log-inl.h +23 -6
  77. data/ext/libcouchbase/src/dump.cc +4 -0
  78. data/ext/libcouchbase/src/getconfig.cc +1 -2
  79. data/ext/libcouchbase/src/handler.cc +65 -27
  80. data/ext/libcouchbase/src/hostlist.cc +35 -7
  81. data/ext/libcouchbase/src/hostlist.h +7 -0
  82. data/ext/libcouchbase/src/http/http-priv.h +2 -0
  83. data/ext/libcouchbase/src/http/http.cc +77 -37
  84. data/ext/libcouchbase/src/http/http_io.cc +19 -2
  85. data/ext/libcouchbase/src/instance.cc +90 -17
  86. data/ext/libcouchbase/src/internal.h +5 -0
  87. data/ext/libcouchbase/src/lcbio/connect.cc +39 -4
  88. data/ext/libcouchbase/src/lcbio/connect.h +27 -0
  89. data/ext/libcouchbase/src/lcbio/ctx.c +49 -23
  90. data/ext/libcouchbase/src/lcbio/ioutils.cc +30 -3
  91. data/ext/libcouchbase/src/lcbio/ioutils.h +2 -0
  92. data/ext/libcouchbase/src/lcbio/manager.cc +44 -8
  93. data/ext/libcouchbase/src/lcbio/manager.h +2 -0
  94. data/ext/libcouchbase/src/lcbio/rw-inl.h +1 -0
  95. data/ext/libcouchbase/src/lcbio/ssl.h +3 -5
  96. data/ext/libcouchbase/src/logging.c +1 -1
  97. data/ext/libcouchbase/src/logging.h +2 -0
  98. data/ext/libcouchbase/src/mc/compress.cc +164 -0
  99. data/ext/libcouchbase/src/mc/compress.h +7 -12
  100. data/ext/libcouchbase/src/mc/mcreq-flush-inl.h +5 -1
  101. data/ext/libcouchbase/src/mc/mcreq.c +11 -1
  102. data/ext/libcouchbase/src/mc/mcreq.h +35 -4
  103. data/ext/libcouchbase/src/mcserver/mcserver.cc +30 -7
  104. data/ext/libcouchbase/src/mcserver/mcserver.h +7 -0
  105. data/ext/libcouchbase/src/mcserver/negotiate.cc +103 -57
  106. data/ext/libcouchbase/src/mcserver/negotiate.h +2 -2
  107. data/ext/libcouchbase/src/mctx-helper.h +11 -0
  108. data/ext/libcouchbase/src/metrics.cc +132 -0
  109. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +2 -1
  110. data/ext/libcouchbase/src/n1ql/n1ql.cc +66 -0
  111. data/ext/libcouchbase/src/newconfig.cc +9 -2
  112. data/ext/libcouchbase/src/operations/counter.cc +2 -1
  113. data/ext/libcouchbase/src/operations/durability-cas.cc +11 -0
  114. data/ext/libcouchbase/src/operations/durability-seqno.cc +3 -0
  115. data/ext/libcouchbase/src/operations/durability.cc +24 -2
  116. data/ext/libcouchbase/src/operations/durability_internal.h +19 -0
  117. data/ext/libcouchbase/src/operations/get.cc +4 -2
  118. data/ext/libcouchbase/src/operations/observe-seqno.cc +1 -0
  119. data/ext/libcouchbase/src/operations/observe.cc +113 -62
  120. data/ext/libcouchbase/src/operations/ping.cc +246 -67
  121. data/ext/libcouchbase/src/operations/remove.cc +2 -1
  122. data/ext/libcouchbase/src/operations/store.cc +17 -14
  123. data/ext/libcouchbase/src/operations/touch.cc +3 -0
  124. data/ext/libcouchbase/src/packetutils.h +68 -4
  125. data/ext/libcouchbase/src/probes.d +132 -161
  126. data/ext/libcouchbase/src/rdb/bigalloc.c +1 -1
  127. data/ext/libcouchbase/src/retryq.cc +6 -2
  128. data/ext/libcouchbase/src/rnd.cc +68 -0
  129. data/ext/libcouchbase/src/rnd.h +39 -0
  130. data/ext/libcouchbase/src/settings.c +27 -0
  131. data/ext/libcouchbase/src/settings.h +67 -3
  132. data/ext/libcouchbase/src/ssl/CMakeLists.txt +0 -12
  133. data/ext/libcouchbase/src/ssl/ssl_common.c +23 -4
  134. data/ext/libcouchbase/src/strcodecs/base64.c +141 -16
  135. data/ext/libcouchbase/src/strcodecs/strcodecs.h +16 -1
  136. data/ext/libcouchbase/src/trace.h +68 -61
  137. data/ext/libcouchbase/src/tracing/span.cc +289 -0
  138. data/ext/libcouchbase/src/tracing/threshold_logging_tracer.cc +171 -0
  139. data/ext/libcouchbase/src/tracing/tracer.cc +53 -0
  140. data/ext/libcouchbase/src/tracing/tracing-internal.h +213 -0
  141. data/ext/libcouchbase/src/utilities.c +5 -0
  142. data/ext/libcouchbase/src/vbucket/CMakeLists.txt +2 -2
  143. data/ext/libcouchbase/src/vbucket/vbucket.c +50 -18
  144. data/ext/libcouchbase/src/views/docreq.cc +26 -1
  145. data/ext/libcouchbase/src/views/docreq.h +17 -0
  146. data/ext/libcouchbase/src/views/viewreq.cc +64 -1
  147. data/ext/libcouchbase/src/views/viewreq.h +21 -0
  148. data/ext/libcouchbase/tests/CMakeLists.txt +6 -6
  149. data/ext/libcouchbase/tests/basic/t_base64.cc +34 -6
  150. data/ext/libcouchbase/tests/basic/t_connstr.cc +14 -0
  151. data/ext/libcouchbase/tests/basic/t_creds.cc +10 -10
  152. data/ext/libcouchbase/tests/basic/t_host.cc +22 -2
  153. data/ext/libcouchbase/tests/basic/t_scram.cc +514 -0
  154. data/ext/libcouchbase/tests/check-all.cc +6 -2
  155. data/ext/libcouchbase/tests/iotests/mock-environment.cc +64 -0
  156. data/ext/libcouchbase/tests/iotests/mock-environment.h +27 -1
  157. data/ext/libcouchbase/tests/iotests/t_confmon.cc +2 -2
  158. data/ext/libcouchbase/tests/iotests/t_forward.cc +8 -0
  159. data/ext/libcouchbase/tests/iotests/t_netfail.cc +124 -0
  160. data/ext/libcouchbase/tests/iotests/t_smoke.cc +1 -1
  161. data/ext/libcouchbase/tests/iotests/t_snappy.cc +316 -0
  162. data/ext/libcouchbase/tests/socktests/socktest.cc +2 -2
  163. data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
  164. data/ext/libcouchbase/tests/socktests/t_manager.cc +1 -1
  165. data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
  166. data/ext/libcouchbase/tools/CMakeLists.txt +1 -1
  167. data/ext/libcouchbase/tools/cbc-handlers.h +17 -0
  168. data/ext/libcouchbase/tools/cbc-n1qlback.cc +7 -4
  169. data/ext/libcouchbase/tools/cbc-pillowfight.cc +408 -100
  170. data/ext/libcouchbase/tools/cbc-proxy.cc +134 -3
  171. data/ext/libcouchbase/tools/cbc-subdoc.cc +1 -2
  172. data/ext/libcouchbase/tools/cbc.cc +113 -8
  173. data/ext/libcouchbase/tools/common/histogram.cc +1 -0
  174. data/ext/libcouchbase/tools/common/options.cc +28 -1
  175. data/ext/libcouchbase/tools/common/options.h +5 -0
  176. data/ext/libcouchbase/tools/docgen/docgen.h +36 -10
  177. data/ext/libcouchbase/tools/docgen/loc.h +5 -4
  178. data/ext/libcouchbase/tools/docgen/seqgen.h +28 -0
  179. data/lib/libcouchbase/ext/libcouchbase/enums.rb +10 -0
  180. data/lib/libcouchbase/n1ql.rb +6 -1
  181. data/lib/libcouchbase/version.rb +1 -1
  182. data/spec/connection_spec.rb +6 -6
  183. metadata +38 -5
  184. data/ext/libcouchbase/cmake/Modules/FindCouchbaseSnappy.cmake +0 -11
  185. data/ext/libcouchbase/src/mc/compress.c +0 -90
  186. data/ext/libcouchbase/tools/common/my_inttypes.h +0 -22
@@ -66,7 +66,7 @@ Connspec::parse_hosts(const char *hostbegin,
66
66
  while (*c) {
67
67
  // get the current host
68
68
  const char *curend;
69
- unsigned curlen, hostlen;
69
+ unsigned curlen, hostlen, hoststart;
70
70
  int rv;
71
71
 
72
72
  /* Seek ahead, chopping off any ',' */
@@ -95,15 +95,30 @@ Connspec::parse_hosts(const char *hostbegin,
95
95
  }
96
96
 
97
97
  size_t colonpos = scratch.find(":");
98
+ size_t rcolonpos = scratch.rfind(":");
98
99
  std::string port;
99
100
 
101
+ hoststart = 0;
100
102
  if (colonpos == std::string::npos) {
101
103
  hostlen = scratch.size();
102
- } else if (colonpos == 0 || colonpos == scratch.size()-1) {
103
- SET_ERROR("First or last character in spec is colon!");
104
+ } else if (colonpos == rcolonpos) {
105
+ if (colonpos == 0 || colonpos == scratch.size() - 1) {
106
+ SET_ERROR("First or last character in spec is colon!");
107
+ } else {
108
+ hostlen = colonpos;
109
+ port = scratch.substr(colonpos + 1);
110
+ }
104
111
  } else {
105
- hostlen = colonpos;
106
- port = scratch.substr(colonpos + 1);
112
+ size_t rbracket = scratch.rfind(']');
113
+ if (scratch[0] == '[' && rbracket != std::string::npos) {
114
+ hoststart = 1;
115
+ hostlen = rbracket - hoststart;
116
+ if (scratch.size() > rbracket + 1) {
117
+ port = scratch.substr(rbracket + 2);
118
+ }
119
+ } else {
120
+ hostlen = scratch.size();
121
+ }
107
122
  }
108
123
 
109
124
  if (m_flags & F_DNSSRV_EXPLICIT) {
@@ -116,7 +131,7 @@ Connspec::parse_hosts(const char *hostbegin,
116
131
 
117
132
  m_hosts.resize(m_hosts.size() + 1);
118
133
  Spechost *dh = &m_hosts.back();
119
- dh->hostname = scratch.substr(0, hostlen);
134
+ dh->hostname = scratch.substr(hoststart, hostlen);
120
135
 
121
136
  if (port.empty()) {
122
137
  continue;
@@ -235,15 +250,35 @@ Connspec::parse_options(
235
250
  } else {
236
251
  SET_ERROR("Invalid value for 'ssl'. Choices are on, off, and no_verify");
237
252
  }
253
+ } else if (!strcmp(key, "truststorepath")) {
254
+ if (! (m_flags & F_SSLSCHEME)) {
255
+ SET_ERROR("Trust store path must be specified with SSL host or scheme");
256
+ }
257
+ m_truststorepath = value;
238
258
  } else if (!strcmp(key, "certpath")) {
239
259
  if (! (m_flags & F_SSLSCHEME)) {
240
260
  SET_ERROR("Certificate path must be specified with SSL host or scheme");
241
261
  }
242
262
  m_certpath = value;
263
+ } else if (!strcmp(key, "keypath")) {
264
+ if (! (m_flags & F_SSLSCHEME)) {
265
+ SET_ERROR("Private key path must be specified with SSL host or scheme");
266
+ }
267
+ m_keypath = value;
243
268
  } else if (!strcmp(key, "console_log_level")) {
244
269
  if (sscanf(value, "%d", &m_loglevel) != 1) {
245
270
  SET_ERROR("console_log_level must be a numeric value");
246
271
  }
272
+ } else if (!strcmp(key, "log_redaction")) {
273
+ int btmp = 0;
274
+ if (!strcmp(value, "on") || !strcmp(value, "true")) {
275
+ btmp = 1;
276
+ } else if (!strcmp(value, "off") || !strcmp(value, "false")) {
277
+ btmp = 0;
278
+ } else if (sscanf(value, "%d", &btmp) != 1) {
279
+ SET_ERROR("log_redaction must have numeric (boolean) value");
280
+ }
281
+ m_logredact = btmp != 0;
247
282
  } else if (!strcmp(key, "dnssrv")) {
248
283
  if ((m_flags & F_DNSSRV_EXPLICIT) == F_DNSSRV_EXPLICIT) {
249
284
  SET_ERROR("Cannot use dnssrv scheme with dnssrv option");
@@ -261,10 +296,23 @@ Connspec::parse_options(
261
296
  } else {
262
297
  m_flags &= ~F_DNSSRV_EXPLICIT;
263
298
  }
299
+ } else if (!strcmp(key, "ipv6")) {
300
+ if (!strcmp(value, "only")) {
301
+ m_ipv6 = LCB_IPV6_ONLY;
302
+ } else if (!strcmp(value, "disabled")) {
303
+ m_ipv6 = LCB_IPV6_DISABLED;
304
+ } else if (!strcmp(value, "allow")) {
305
+ m_ipv6 = LCB_IPV6_ALLOW;
306
+ } else {
307
+ SET_ERROR("Value for ipv6 must be 'disabled', 'allow', or 'only'");
308
+ }
264
309
  } else {
265
310
  m_ctlopts.push_back(std::make_pair(key, value));
266
311
  }
267
312
  }
313
+ if (!m_keypath.empty() && m_certpath.empty()) {
314
+ SET_ERROR("Private key path must be specified with certificate path");
315
+ }
268
316
 
269
317
  return LCB_SUCCESS;
270
318
  }
@@ -61,7 +61,7 @@ struct Spechost {
61
61
  class LCB_CLASS_EXPORT Connspec {
62
62
  public:
63
63
  typedef std::vector<std::pair<std::string,std::string> > Options;
64
- Connspec() : m_sslopts(0), m_implicit_port(0), m_loglevel(0), m_flags(0) {}
64
+ Connspec() : m_sslopts(0), m_implicit_port(0), m_loglevel(0), m_logredact(false), m_flags(0), m_ipv6(LCB_IPV6_DISABLED) {}
65
65
 
66
66
  lcb_error_t parse(const char *connstr, const char **errmsg = NULL);
67
67
  lcb_error_t load(const lcb_create_st&);
@@ -92,24 +92,31 @@ public:
92
92
  const std::string& bucket() const { return m_bucket; }
93
93
  const std::string& username() const { return m_username; }
94
94
  const std::string& password() const { return m_password; }
95
+ const std::string& truststorepath() const { return m_truststorepath; }
95
96
  const std::string& certpath() const { return m_certpath; }
97
+ const std::string& keypath() const { return m_keypath; }
96
98
  unsigned sslopts() const { return m_sslopts; }
97
99
  const Options& options() const { return m_ctlopts; }
98
100
  unsigned loglevel() const { return m_loglevel; }
101
+ bool logredact() const { return m_logredact; }
99
102
  const std::string& connstr() const { return m_connstr; }
100
103
  void clear_hosts() { m_hosts.clear(); }
101
104
  void add_host(const Spechost& host) { m_hosts.push_back(host); }
105
+ lcb_ipv6_t ipv6_policy() const { return m_ipv6; }
102
106
  private:
103
107
  Options m_ctlopts;
104
108
  std::string m_bucket;
105
109
  std::string m_username;
106
110
  std::string m_password;
111
+ std::string m_truststorepath;
107
112
  std::string m_certpath;
113
+ std::string m_keypath;
108
114
  std::string m_connstr;
109
115
  unsigned m_sslopts; /**< SSL Options */
110
116
  std::vector<Spechost> m_hosts;
111
117
  lcb_U16 m_implicit_port; /**< Implicit port, based on scheme */
112
118
  int m_loglevel; /* cached loglevel */
119
+ bool m_logredact;
113
120
 
114
121
  inline lcb_error_t parse_options(
115
122
  const char *options, const char *optend, const char **errmsg);
@@ -118,6 +125,7 @@ private:
118
125
 
119
126
  std::set<int> m_transports;
120
127
  unsigned m_flags; /**< Internal flags */
128
+ lcb_ipv6_t m_ipv6;
121
129
  };
122
130
 
123
131
  #define LCB_SPECSCHEME_RAW "couchbase+explicit://"
@@ -0,0 +1,386 @@
1
+ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2017-2018 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "internal.h"
19
+
20
+ void lcbcrypto_ref(lcbcrypto_PROVIDER *provider)
21
+ {
22
+ provider->_refcnt++;
23
+ }
24
+
25
+ void lcbcrypto_unref(lcbcrypto_PROVIDER *provider)
26
+ {
27
+ provider->_refcnt--;
28
+ if (provider->_refcnt == 0 && provider->destructor) {
29
+ provider->destructor(provider);
30
+ }
31
+ }
32
+
33
+ void lcbcrypto_register(lcb_t instance, const char *name, lcbcrypto_PROVIDER *provider)
34
+ {
35
+ std::map< std::string, lcbcrypto_PROVIDER * >::iterator old = instance->crypto->find(name);
36
+ if (old != instance->crypto->end()) {
37
+ lcbcrypto_unref(old->second);
38
+ }
39
+ lcbcrypto_ref(provider);
40
+ (*instance->crypto)[name] = provider;
41
+ }
42
+
43
+ void lcbcrypto_unregister(lcb_t instance, const char *name)
44
+ {
45
+ std::map< std::string, lcbcrypto_PROVIDER * >::iterator old = instance->crypto->find(name);
46
+ if (old != instance->crypto->end()) {
47
+ lcbcrypto_unref(old->second);
48
+ instance->crypto->erase(old);
49
+ }
50
+ }
51
+
52
+ static bool lcbcrypto_is_valid(lcbcrypto_PROVIDER *provider)
53
+ {
54
+ if (!(provider && provider->_refcnt > 0)) {
55
+ return false;
56
+ }
57
+ if (provider->version != 0) {
58
+ return false;
59
+ }
60
+ if (provider->v.v0.sign && provider->v.v0.verify_signature == NULL) {
61
+ return false;
62
+ }
63
+ return provider->v.v0.load_key && provider->v.v0.encrypt && provider->v.v0.decrypt;
64
+ }
65
+
66
+ #define PROVIDER_LOAD_KEY(provider, type, keyid, key, nkey) \
67
+ (provider)->v.v0.load_key((provider), (type), (keyid), (key), (nkey))
68
+
69
+ #define PROVIDER_NEED_SIGN(provider) (provider)->v.v0.sign != NULL
70
+ #define PROVIDER_SIGN(provider, parts, nparts, sig, nsig) \
71
+ (provider)->v.v0.sign((provider), (parts), (nparts), (sig), (nsig));
72
+ #define PROVIDER_VERIFY_SIGNATURE(provider, parts, nparts, sig, nsig) \
73
+ (provider)->v.v0.verify_signature((provider), (parts), (nparts), (sig), (nsig));
74
+
75
+ #define PROVIDER_NEED_IV(provider) (provider)->v.v0.generate_iv != NULL
76
+ #define PROVIDER_GENERATE_IV(provider, iv, niv) (provider)->v.v0.generate_iv((provider), (iv), (niv))
77
+
78
+ #define PROVIDER_ENCRYPT(provider, ptext, nptext, key, nkey, iv, niv, ctext, nctext) \
79
+ (provider)->v.v0.encrypt((provider), (ptext), (nptext), (key), (nkey), (iv), (niv), (ctext), (nctext));
80
+ #define PROVIDER_DECRYPT(provider, ctext, nctext, key, nkey, iv, niv, ptext, nptext) \
81
+ (provider)->v.v0.decrypt((provider), (ctext), (nctext), (key), (nkey), (iv), (niv), (ptext), (nptext));
82
+
83
+ #define PROVIDER_RELEASE_BYTES(provider, bytes) \
84
+ if ((bytes) && (provider)->v.v0.release_bytes) { \
85
+ (provider)->v.v0.release_bytes((provider), (bytes)); \
86
+ }
87
+
88
+
89
+ static lcbcrypto_PROVIDER *lcb_get_provider(const lcb_st *instance, const std::string &alg)
90
+ {
91
+ const lcb_st::lcb_ProviderMap::iterator provider_iterator = (*instance->crypto).find(alg);
92
+ return provider_iterator != (*instance->crypto).end() ? provider_iterator->second : NULL;
93
+ }
94
+
95
+ lcb_error_t lcbcrypto_encrypt_fields(lcb_t instance, lcbcrypto_CMDENCRYPT *cmd)
96
+ {
97
+ cmd->out = NULL;
98
+ cmd->nout = 0;
99
+
100
+ Json::Value jdoc;
101
+ if (!Json::Reader().parse(cmd->doc, cmd->doc + cmd->ndoc, jdoc)) {
102
+ return LCB_EINVAL;
103
+ }
104
+ bool changed = false;
105
+ std::string prefix = (cmd->prefix == NULL) ? "__crypt_" : cmd->prefix;
106
+ for (size_t ii = 0; ii < cmd->nfields; ii++) {
107
+ lcbcrypto_FIELDSPEC *field = cmd->fields + ii;
108
+ lcb_error_t rc;
109
+ uint8_t *key = NULL;
110
+ size_t nkey = 0;
111
+
112
+ lcbcrypto_PROVIDER *provider = lcb_get_provider(instance, field->alg);
113
+ if (!lcbcrypto_is_valid(provider)) {
114
+ continue;
115
+ }
116
+
117
+ rc = PROVIDER_LOAD_KEY(provider, LCBCRYPTO_KEY_ENCRYPT, field->kid, &key, &nkey);
118
+ if (rc != LCB_SUCCESS) {
119
+ PROVIDER_RELEASE_BYTES(provider, key);
120
+ continue;
121
+ }
122
+
123
+ if (jdoc.isMember(field->name)) {
124
+ std::string contents = Json::FastWriter().write(jdoc[field->name]);
125
+ Json::Value encrypted;
126
+ int ret;
127
+
128
+ uint8_t *iv = NULL;
129
+ char *biv = NULL;
130
+ size_t niv = 0;
131
+ lcb_SIZE nbiv = 0;
132
+ if (PROVIDER_NEED_IV(provider)) {
133
+ rc = PROVIDER_GENERATE_IV(provider, &iv, &niv);
134
+ if (rc != 0) {
135
+ PROVIDER_RELEASE_BYTES(provider, iv);
136
+ continue;
137
+ }
138
+ ret = lcb_base64_encode2(reinterpret_cast< char * >(iv), niv, &biv, &nbiv);
139
+ if (ret < 0) {
140
+ free(biv);
141
+ PROVIDER_RELEASE_BYTES(provider, iv);
142
+ continue;
143
+ }
144
+ encrypted["iv"] = biv;
145
+ }
146
+ const uint8_t *ptext = reinterpret_cast< const uint8_t * >(contents.c_str());
147
+ uint8_t *ctext = NULL;
148
+ size_t nptext = contents.size(), nctext = 0;
149
+ rc = PROVIDER_ENCRYPT(provider, ptext, nptext, key, nkey, iv, niv, &ctext, &nctext);
150
+ PROVIDER_RELEASE_BYTES(provider, iv);
151
+ if (rc != LCB_SUCCESS) {
152
+ PROVIDER_RELEASE_BYTES(provider, ctext);
153
+ continue;
154
+ }
155
+ char *btext = NULL;
156
+ lcb_SIZE nbtext = 0;
157
+ ret = lcb_base64_encode2(reinterpret_cast< char * >(ctext), nctext, &btext, &nbtext);
158
+ PROVIDER_RELEASE_BYTES(provider, ctext);
159
+ if (ret < 0) {
160
+ free(btext);
161
+ continue;
162
+ }
163
+ encrypted["ciphertext"] = btext;
164
+
165
+ if (PROVIDER_NEED_SIGN(provider)) {
166
+ lcbcrypto_SIGV parts[4] = {};
167
+ size_t nparts = 0;
168
+ uint8_t *sig = NULL;
169
+ size_t nsig = 0;
170
+
171
+ parts[nparts].data = reinterpret_cast< const uint8_t * >(field->kid);
172
+ parts[nparts].len = strlen(field->kid);
173
+ nparts++;
174
+ parts[nparts].data = reinterpret_cast< const uint8_t * >(field->alg);
175
+ parts[nparts].len = strlen(field->alg);
176
+ nparts++;
177
+ if (biv) {
178
+ parts[nparts].data = reinterpret_cast< const uint8_t * >(biv);
179
+ parts[nparts].len = nbiv;
180
+ nparts++;
181
+ }
182
+ parts[nparts].data = reinterpret_cast< const uint8_t * >(btext);
183
+ parts[nparts].len = nbtext;
184
+ nparts++;
185
+
186
+ rc = PROVIDER_SIGN(provider, parts, nparts, &sig, &nsig);
187
+ if (rc != LCB_SUCCESS) {
188
+ PROVIDER_RELEASE_BYTES(provider, sig);
189
+ continue;
190
+ }
191
+ char *bsig = NULL;
192
+ lcb_SIZE nbsig = 0;
193
+ ret = lcb_base64_encode2(reinterpret_cast< char * >(sig), nsig, &bsig, &nbsig);
194
+ PROVIDER_RELEASE_BYTES(provider, sig);
195
+ if (ret < 0) {
196
+ free(bsig);
197
+ continue;
198
+ }
199
+ encrypted["sig"] = bsig;
200
+ free(bsig);
201
+ }
202
+ free(biv);
203
+ free(btext);
204
+ encrypted["kid"] = field->kid;
205
+ encrypted["alg"] = field->alg;
206
+ jdoc[prefix + field->name] = encrypted;
207
+ jdoc.removeMember(field->name);
208
+ changed = true;
209
+ }
210
+ }
211
+ if (changed) {
212
+ std::string doc = Json::FastWriter().write(jdoc);
213
+ cmd->out = strdup(doc.c_str());
214
+ cmd->nout = strlen(cmd->out);
215
+ }
216
+ return LCB_SUCCESS;
217
+ }
218
+
219
+ lcb_error_t lcbcrypto_decrypt_fields(lcb_t instance, lcbcrypto_CMDDECRYPT *cmd)
220
+ {
221
+ cmd->out = NULL;
222
+ cmd->nout = 0;
223
+
224
+ Json::Value jdoc;
225
+ if (!Json::Reader().parse(cmd->doc, cmd->doc + cmd->ndoc, jdoc)) {
226
+ return LCB_EINVAL;
227
+ }
228
+
229
+ if (!jdoc.isObject()) {
230
+ return LCB_EINVAL;
231
+ }
232
+
233
+ bool changed = false;
234
+ std::string prefix = (cmd->prefix == NULL) ? "__crypt_" : cmd->prefix;
235
+
236
+ const Json::Value::Members names = jdoc.getMemberNames();
237
+ for (Json::Value::Members::const_iterator ii = names.begin(); ii != names.end(); ii++) {
238
+ const std::string &name = *ii;
239
+ if (name.size() <= prefix.size()) {
240
+ continue;
241
+ }
242
+ if (prefix.compare(0, prefix.size(), name, 0, prefix.size()) != 0) {
243
+ continue;
244
+ }
245
+ Json::Value &encrypted = jdoc[name];
246
+ if (!encrypted.isObject()) {
247
+ continue;
248
+ }
249
+
250
+ Json::Value &jalg = encrypted["alg"];
251
+ if (!jalg.isString()) {
252
+ continue;
253
+ }
254
+ const std::string &alg = jalg.asString();
255
+
256
+ Json::Value &jkid = encrypted["kid"];
257
+ if (!jkid.isString()) {
258
+ continue;
259
+ }
260
+ const std::string &kid = jkid.asString();
261
+
262
+ Json::Value &jiv = encrypted["iv"];
263
+ const char *biv = NULL;
264
+ size_t nbiv = 0;
265
+ if (jiv.isString()) {
266
+ biv = jiv.asCString();
267
+ nbiv = strlen(biv);
268
+ }
269
+
270
+ int ret;
271
+ lcb_error_t rc;
272
+
273
+ lcbcrypto_PROVIDER *provider = lcb_get_provider(instance, alg);
274
+ if (!lcbcrypto_is_valid(provider)) {
275
+ continue;
276
+ }
277
+ Json::Value &jctext = encrypted["ciphertext"];
278
+ if (!jctext.isString()) {
279
+ continue;
280
+ }
281
+ const std::string &btext = jctext.asString();
282
+
283
+ if (PROVIDER_NEED_SIGN(provider)) {
284
+ Json::Value &jsig = encrypted["sig"];
285
+ if (!jsig.isString()) {
286
+ /* TODO: warn about missing signature? */
287
+ continue;
288
+ }
289
+ uint8_t *sig = NULL;
290
+ lcb_SIZE nsig = 0;
291
+ const std::string &bsig = jsig.asString();
292
+ ret = lcb_base64_decode2(bsig.c_str(), bsig.size(), reinterpret_cast< char ** >(&sig), &nsig);
293
+ if (ret < 0) {
294
+ PROVIDER_RELEASE_BYTES(provider, sig);
295
+ continue;
296
+ }
297
+
298
+ lcbcrypto_SIGV parts[4] = {};
299
+ size_t nparts = 0;
300
+
301
+ parts[nparts].data = reinterpret_cast< const uint8_t * >(kid.c_str());
302
+ parts[nparts].len = kid.size();
303
+ nparts++;
304
+ parts[nparts].data = reinterpret_cast< const uint8_t * >(alg.c_str());
305
+ parts[nparts].len = alg.size();
306
+ nparts++;
307
+ if (biv) {
308
+ parts[nparts].data = reinterpret_cast< const uint8_t * >(biv);
309
+ parts[nparts].len = nbiv;
310
+ nparts++;
311
+ }
312
+ parts[nparts].data = reinterpret_cast< const uint8_t * >(btext.c_str());
313
+ parts[nparts].len = btext.size();
314
+ nparts++;
315
+
316
+ rc = PROVIDER_VERIFY_SIGNATURE(provider, parts, nparts, sig, nsig);
317
+ free(sig);
318
+ if (rc != LCB_SUCCESS) {
319
+ continue;
320
+ }
321
+ }
322
+
323
+ uint8_t *ctext = NULL;
324
+ lcb_SIZE nctext = 0;
325
+ ret = lcb_base64_decode2(btext.c_str(), btext.size(), reinterpret_cast< char ** >(&ctext), &nctext);
326
+ if (ret < 0) {
327
+ continue;
328
+ }
329
+
330
+ uint8_t *key = NULL;
331
+ size_t nkey = 0;
332
+ rc = PROVIDER_LOAD_KEY(provider, LCBCRYPTO_KEY_DECRYPT, kid.c_str(), &key, &nkey);
333
+ if (rc != LCB_SUCCESS) {
334
+ free(ctext);
335
+ PROVIDER_RELEASE_BYTES(provider, key);
336
+ continue;
337
+ }
338
+
339
+ uint8_t *iv = NULL;
340
+ lcb_SIZE niv = 0;
341
+ if (biv) {
342
+ ret = lcb_base64_decode2(biv, nbiv, reinterpret_cast< char ** >(&iv), &niv);
343
+ if (ret < 0) {
344
+ free(ctext);
345
+ PROVIDER_RELEASE_BYTES(provider, key);
346
+ continue;
347
+ }
348
+ }
349
+
350
+ uint8_t *ptext = NULL;
351
+ size_t nptext = 0;
352
+ rc = PROVIDER_DECRYPT(provider, ctext, nctext, key, nkey, iv, niv, &ptext, &nptext);
353
+ PROVIDER_RELEASE_BYTES(provider, key);
354
+ free(ctext);
355
+ if (rc != LCB_SUCCESS) {
356
+ PROVIDER_RELEASE_BYTES(provider, ptext);
357
+ continue;
358
+ }
359
+ Json::Value frag;
360
+ char *json = reinterpret_cast< char * >(ptext);
361
+ bool valid_json = Json::Reader().parse(json, json + nptext, frag);
362
+ PROVIDER_RELEASE_BYTES(provider, ptext);
363
+ if (!valid_json) {
364
+ continue;
365
+ }
366
+ jdoc[name.substr(prefix.size())] = frag;
367
+ jdoc.removeMember(name);
368
+ changed = true;
369
+ }
370
+ if (changed) {
371
+ std::string doc = Json::FastWriter().write(jdoc);
372
+ cmd->out = strdup(doc.c_str());
373
+ cmd->nout = strlen(cmd->out);
374
+ }
375
+ return LCB_SUCCESS;
376
+ }
377
+
378
+ lcb_error_t lcbcrypto_encrypt_document(lcb_t, lcbcrypto_CMDENCRYPT *)
379
+ {
380
+ return LCB_NOT_SUPPORTED;
381
+ }
382
+
383
+ lcb_error_t lcbcrypto_decrypt_document(lcb_t, lcbcrypto_CMDDECRYPT *)
384
+ {
385
+ return LCB_NOT_SUPPORTED;
386
+ }