identt
LookupService.hpp
Go to the documentation of this file.
1 
33 #ifndef _IDENTT_QUERY_LOOKUP_SERVICE_HPP_
34 #define _IDENTT_QUERY_LOOKUP_SERVICE_HPP_
35 
36 #include <query/QueryBase.hpp>
38 #include <store/LookupService.hpp>
39 
40 // #include <rapidjson/rapidjson.h>
41 #include <rapidjson/writer.h>
42 #include <rapidjson/stringbuffer.h>
43 #include <rapidjson/pointer.h>
44 
45 namespace identt {
46 namespace query {
47 
48 template <class HttpServerT>
50  public identt::query::ServiceBase<HttpServerT> {
51 public:
52 
73  identt::utils::SharedTable::pointer stptr,
74  typename std::shared_ptr<HttpServerT> server,
75  ::identt::query::HelpQuery::pointer helpquery,
76  unsigned int scope)
77  : identt::query::ServiceBase<HttpServerT>(IDENTT_SERVICE_SCOPE_HTTP | IDENTT_SERVICE_SCOPE_HTTPS)
78  {
79  if (!(this->myscope & scope)) return; // scope mismatch
80 
81  // Endpoint : POST _matrix/identity/api/v1/lookup
82  helpquery->add({scope,"POST _matrix/identity/api/v1/lookup", {
83  "Look up the Matrix user ID for a 3pid.",
84  "query parameters: medium, address",
85  "medium Required. The literal string email.",
86  "address Required. The email address being looked up.",
87  "accesskey Required if lookup_requires_accesskey is set."
88  }
89  });
90 
91  server->resource["/_matrix/identity/api/v1/lookup$"]["POST"]
92  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
93  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
94  try {
95  LOG(INFO) << request->path;
96  std::string err;
97  bool use_json = this->JsonRequest(request);
98 
99  identt::query::LookupDataT lact;
100  if (use_json)
101  {
102  int stat = json2pb( request->content.string() , lact.mutable_query() , err);
103  if (stat<0) throw SydentException("Bad Json Format",M_BAD_JSON);
104  } else {
105  form2pb( request->content.string() , lact.mutable_query() ); // throws on error
106  }
107  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
108 
109  // action
110 
111  // if accesskey is shared_secret it is server request, else check
112  if (stptr->lookup_requires_key.Get()) {
113  bool is_server_query = false;
114  auto it=request->header.find("Shared-Secret");
115  if (it!=request->header.end()) {
116  is_server_query = (it->second == stptr->shared_secret.Get());
117  }
118  if (!is_server_query ) {
120  aservice.VerifyAccessKeyAction(stptr, lact.mutable_query()->accesskey());
121  }
122  }
123 
125  lservice.LookupAction(stptr, &lact);
126 
127  // aftermath
128  std::string output;
129  ::identt::query::PubKeyT pubkey;
130 
131  // set owners
132  pubkey.set_owner(stptr->hostname.Get());
133  pubkey.set_algo(THREEPID_DEFAULT_ALGO);
134  pubkey.set_identifier(THREEPID_DEFAULT_ALGO_ID);
135 
136  // test data
137  std::vector<::identt::query::SignatureT> signatures;
138  lservice.AddSign(stptr, lact.mutable_result() , &pubkey, output,signatures);
139  if (!output.length()) output="{}";
140 
141  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
142  } catch (SydentException& e)
143  {
144  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
145  std::string output = err2json(SydentErrors.at(ecode),e.what());
146  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
147  } catch (identt::JdException& e)
148  {
149  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
150  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
151  } catch (std::exception& e)
152  {
153  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
154  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
155  } catch (...)
156  {
157  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
158  }
159  });
160  };
161 
162  // Endpoint : GET _matrix/identity/api/v1/lookup
163  helpquery->add({scope,"GET _matrix/identity/api/v1/lookup", {
164  "Look up the Matrix user ID for a 3pid.",
165  "This is the GET version of lookup",
166  "query parameters: medium, address",
167  "medium Required. The literal string email.",
168  "address Required. The email address being looked up.",
169  "accesskey Required if lookup_requires_accesskey is set."
170  }
171  });
172 
173  server->resource["/_matrix/identity/api/v1/lookup\\\?(.*)$"]["GET"]
174  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
175  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
176  try {
177  LOG(INFO) << request->path;
178  std::string err;
179  std::string params = request->path_match[1];
180  identt::query::LookupDataT lact;
181  form2pb( params , lact.mutable_query()); // throws on error
182 
183  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
184 
185  // action
186 
187  // if accesskey is shared_secret it is server request, else check
188  if (stptr->lookup_requires_key.Get()) {
189  bool is_server_query = false;
190  auto it=request->header.find("Shared-Secret");
191  if (it!=request->header.end()) {
192  is_server_query = (it->second == stptr->shared_secret.Get());
193  }
194  if (!is_server_query ) {
196  aservice.VerifyAccessKeyAction(stptr, lact.mutable_query()->accesskey());
197  }
198  }
199 
201  lservice.LookupAction(stptr, &lact);
202 
203  // aftermath
204  std::string output;
205  ::identt::query::PubKeyT pubkey;
206 
207  // set owners
208  pubkey.set_owner(stptr->hostname.Get());
209  pubkey.set_algo(THREEPID_DEFAULT_ALGO);
210  pubkey.set_identifier(THREEPID_DEFAULT_ALGO_ID);
211 
212  // test data
213  std::vector<::identt::query::SignatureT> signatures;
214  lservice.AddSign(stptr, lact.mutable_result() , &pubkey, output,signatures);
215 
216  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
217  } catch (SydentException& e)
218  {
219  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
220  std::string output = err2json(SydentErrors.at(ecode),e.what());
221  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
222  } catch (identt::JdException& e)
223  {
224  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
225  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
226  } catch (std::exception& e)
227  {
228  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
229  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
230  } catch (...)
231  {
232  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
233  }
234  });
235  };
236 
237  // Endpoint : POST _matrix/identity/api/v1/bulk_lookup
238  helpquery->add({scope,"POST _matrix/identity/api/v1/bulk_lookup", {
239  "Look up the Matrix user ID for a list of 3pid.",
240  "query parameters: list of {medium, address}",
241  "medium Required. The literal string email.",
242  "address Required. The email address being looked up.",
243  "accesskey Required if lookup_requires_accesskey is set."
244  }
245  });
246 
247  server->resource["/_matrix/identity/api/v1/bulk_lookup$"]["POST"]
248  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
249  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
250  try {
251  LOG(INFO) << request->path;
252  std::string err;
253  bool use_json = this->JsonRequest(request);
254 
255  identt::query::BulkLookupDataT blact;
256  if (use_json)
257  {
258  int stat = json2pb( request->content.string() , blact.mutable_query() , err);
259  if (stat<0) throw SydentException("Bad Json Format",M_BAD_JSON);
260  } else {
261  throw SydentException("Only Json Supported",M_BAD_JSON);
262  }
263  DLOG(INFO) << blact.DebugString();
264  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
265 
266  // action
267 
268  // if accesskey is shared_secret it is server request, else check
269  if (stptr->lookup_requires_key.Get()) {
270  bool is_server_query = false;
271  auto it=request->header.find("Shared-Secret");
272  if (it!=request->header.end()) {
273  is_server_query = (it->second == stptr->shared_secret.Get());
274  }
275  if (!is_server_query ) {
277  aservice.VerifyAccessKeyAction(stptr, blact.mutable_query()->accesskey());
278  }
279  }
280 
282  lservice.BulkLookupAction(stptr, &blact);
283  std::string instring;
284  this->BulkLookupJson(blact.mutable_result(),instring);
285 
286  // aftermath
287  std::string output;
288  ::identt::query::PubKeyT pubkey;
289 
290  // set owners
291  pubkey.set_owner(stptr->hostname.Get());
292  pubkey.set_algo(THREEPID_DEFAULT_ALGO);
293  pubkey.set_identifier(THREEPID_DEFAULT_ALGO_ID);
294 
295 
296  // test data
297 
298  std::vector<::identt::query::SignatureT> signatures;
299  lservice.AddSign(stptr, instring , &pubkey, output,signatures);
300  if (!output.length()) output="{}";
301 
302  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
303  } catch (SydentException& e)
304  {
305  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
306  std::string output = err2json(SydentErrors.at(ecode),e.what());
307  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
308  } catch (identt::JdException& e)
309  {
310  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
311  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
312  } catch (std::exception& e)
313  {
314  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
315  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
316  } catch (...)
317  {
318  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
319  }
320  });
321  };
322 
323  }
324 
325 private:
338  void BulkLookupJson(identt::query::BulkLookupResultT* bulkres, std::string& output)
339  {
341  rapidjson::Document::AllocatorType& allocator = d.GetAllocator();
342  rapidjson::Pointer("/threepids").Create(d , allocator );
343  rapidjson::Value* threepids = rapidjson::Pointer("/threepids").Get(d);
344  if (!threepids->IsArray()) threepids->SetArray();
345 
346  for (auto& res : bulkres->threepids() ) {
348  entry
349  .PushBack( rapidjson::StringRef( res.medium().c_str() ) , allocator )
350  .PushBack( rapidjson::StringRef( res.address().c_str() ) , allocator )
351  .PushBack( rapidjson::StringRef( res.mxid().c_str() ) , allocator );
352  threepids->PushBack(entry,allocator);
353  }
354  rapidjson::StringBuffer buffer;
355  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
356  d.Accept(writer);
357  output.clear();
358  output.append(buffer.GetString(), buffer.GetSize());
359  }
360 
361 };
362 } // namespace query
363 } // namespace identt
364 
365 #endif // _IDENTT_QUERY_LOOKUP_SERVICE_HPP_
void HttpOKAction(typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request, int ec, const char *em, const char *content_type, std::string &payload, bool add_cors)
HttpOKAction : OK Action template.
Definition: ServiceBase.hpp:154
Allocator AllocatorType
Allocator type from template parameter.
Definition: document.h:2078
array
Definition: rapidjson.h:608
Sydent Exceptions.
Definition: SydentQuery.hpp:91
void HttpErrorAction(typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request, int ec, const char *em)
HttpErrorAction : Error Action Template no payload maybe template.
Definition: ServiceBase.hpp:85
Definition: BaseUtils.hpp:52
GenericValue< UTF8<> > Value
GenericValue with UTF8 encoding.
Definition: document.h:2060
Definition: ServiceBase.hpp:55
Definition: CryptoBase.hpp:49
GenericDocument< UTF8<> > Document
GenericDocument with UTF8 encoding.
Definition: document.h:2452
Definition: BaseUtils.hpp:89
void BulkLookupAction(::identt::utils::SharedTable::pointer stptr, ::identt::query::BulkLookupDataT *blact)
BulkLookupAction : Service Endpoint Lookup.
Definition: LookupService.cc:62
void form2pb(const std::string &form, google::protobuf::Message *msg)
form2pb : Convert url-encoded form to protobuf
Definition: ProtoForm.cc:129
LookupService(identt::utils::SharedTable::pointer stptr, typename std::shared_ptr< HttpServerT > server, ::identt::query::HelpQuery::pointer helpquery, unsigned int scope)
LookupService : constructor.
Definition: LookupService.hpp:72
GenericStringRef< CharType > StringRef(const CharType *str)
Mark a character pointer as constant string.
Definition: document.h:354
void VerifyAccessKeyAction(::identt::utils::SharedTable::pointer stptr, std::string akey)
VerifyAccessKeyAction : verify the access key.
Definition: AccessKeyService.cc:44
Definition: LookupService.hpp:43
std::string err2json(const std::string errorcode, const std::string error)
err2json : Generate a Json for Error Message
Definition: ProtoJson.cc:511
void AddSign(::identt::utils::SharedTable::pointer stptr, const google::protobuf::Message *result, const ::identt::query::PubKeyT *pubkey, std::string &output, SignatureListT &signatures)
AddSign: Add Signature pb, also adds older signatures.
bool JsonRequest(typename HttpServerT::ReqPtr request)
JsonRequest : Check if request is json from Content-Type and Accept fields.
Definition: ServiceBase.hpp:178
Definition: LookupService.hpp:49
void LookupAction(::identt::utils::SharedTable::pointer stptr, ::identt::query::LookupDataT *lact)
LookupAction : Service Endpoint Lookup.
Definition: LookupService.cc:47
int json2pb(const std::string &json, google::protobuf::Message *msg, std::string &err)
json2pb : Convert json to protobuf
Definition: ProtoJson.cc:446
Definition: AccessKeyService.hpp:42