identt
ThreePidService.hpp
Go to the documentation of this file.
1 
33 #ifndef _IDENTT_QUERY_THREEPID_SERVICE_HPP_
34 #define _IDENTT_QUERY_THREEPID_SERVICE_HPP_
35 
36 #include <query/QueryBase.hpp>
38 #include <hrpc/HrpcClient.hpp>
39 
40 namespace identt {
41 namespace query {
42 
43 template <class HttpServerT>
44 class ThreePidService : public identt::query::ServiceBase<HttpServerT> {
45 public:
46 
67  identt::utils::SharedTable::pointer stptr,
68  typename std::shared_ptr<HttpServerT> server,
69  ::identt::query::HelpQuery::pointer helpquery,
70  unsigned int scope)
71  : identt::query::ServiceBase<HttpServerT>(IDENTT_SERVICE_SCOPE_HTTP | IDENTT_SERVICE_SCOPE_HTTPS)
72  {
73  if (!(this->myscope & scope)) return; // scope mismatch
74 
75  // Endpoint : POST _matrix/identity/api/v1/3pid/getValidated3pid
76  helpquery->add({scope,"POST _matrix/identity/api/v1/3pid/getValidated3pid", {
77  "A client can check whether ownership of a 3pid was validated by making a",
78  " request passing the sid and client_secret as query parameters from the requestToken call",
79  "params : sid , client_secret"
80  }
81  });
82  server->resource["/_matrix/identity/api/v1/3pid/getValidated3pid$"]["POST"]
83  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
84  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
85  try {
86  LOG(INFO) << request->path;
87  std::string err;
88  bool use_json = this->JsonRequest(request);
89 
90  identt::query::GetValidated3pidDataT gva;
91  if (use_json)
92  {
93  int stat = json2pb( request->content.string() , gva.mutable_subtok() , err);
94  if (stat<0) throw SydentException("Bad Json Format",M_BAD_JSON);
95  } else {
96  form2pb( request->content.string() , gva.mutable_subtok()); // throws on error
97  }
98  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
99  identt::query::ValidatedAtT valresult;
100 
101  // action
102  if (gva.mutable_subtok()->sid().length()==0)
103  throw ::identt::query::SydentException("sid value required", M_MISSING_PARAMS);
104  if (gva.mutable_subtok()->client_secret().length()==0)
105  throw ::identt::query::SydentException("client_secret value required", M_MISSING_PARAMS);
106 
107  if (stptr->is_master.Get())
108  {
110  tservice.GetValidated3pidAction(stptr, &gva);
111  } else {
112  identt::hrpc::HrpcClient hclient;
113  hclient.SendToMaster(stptr,::identt::hrpc::M_GETVALIDATED3PID,&gva);
114  }
115 
116  // aftermath
117  std::string output;
118  pb2json(gva.mutable_valresult() , output);
119  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
120  } catch (SydentException& e)
121  {
122  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
123  std::string output = err2json(SydentErrors.at(ecode),e.what());
124  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
125  } catch (identt::JdException& e)
126  {
127  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
128  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
129  } catch (std::exception& e)
130  {
131  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
132  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
133  } catch (...)
134  {
135  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
136  }
137  });
138  };
139 
140  // Endpoint : GET _matrix/identity/api/v1/3pid/getValidated3pid
141  helpquery->add({scope,"GET _matrix/identity/api/v1/3pid/getValidated3pid", {
142  "This is the GET version of getValidated3pid",
143  "A client can check whether ownership of a 3pid was validated by making a",
144  " request passing the sid and client_secret as query parameters from the requestToken call",
145  "params : sid , client_secret"
146  }
147  });
148 
149  server->resource["/_matrix/identity/api/v1/3pid/getValidated3pid\\\?(.*)$"]["GET"]
150  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
151  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
152  try {
153  LOG(INFO) << request->path;
154  std::string err;
155  std::string params = request->path_match[1];
156 
157  identt::query::GetValidated3pidDataT gva;
158  form2pb( params , gva.mutable_subtok()); // throws on error
159  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
160 
161  // action
162  if (stptr->is_master.Get())
163  {
165  tservice.GetValidated3pidAction(stptr, &gva);
166  } else {
167  identt::hrpc::HrpcClient hclient;
168  hclient.SendToMaster(stptr,::identt::hrpc::M_GETVALIDATED3PID,&gva);
169  }
170 
171  // aftermath
172  std::string output;
173  pb2json(gva.mutable_valresult() , output);
174  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
175  } catch (SydentException& e)
176  {
177  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
178  std::string output = err2json(SydentErrors.at(ecode),e.what());
179  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
180  } catch (identt::JdException& e)
181  {
182  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
183  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
184  } catch (std::exception& e)
185  {
186  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
187  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
188  } catch (...)
189  {
190  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
191  }
192  });
193  };
194 
195  // Endpoint : POST _matrix/identity/api/v1/3pid/bind
196  helpquery->add({scope,"POST _matrix/identity/api/v1/3pid/bind", {
197  "An association between a session and a Matrix user ID can be published by making a request to this.",
198  "params: sid , client_secret , mxid",
199  "where mxid takes the form @name:domain.com",
200  "If the session is still valid, this will publish an association between the 3pids validated on that",
201  "session and the passed Matrix user ID. Future calls to /lookup for any of the session’s 3pids",
202  "will return this association. If the 3pid has not yet been validated, the HTTP request will be",
203  "rejected, and the association will not be established. If the sid and client_secret were not recognised",
204  "or were not correct, an error will be returned."
205  }
206  });
207 
208  server->resource["/_matrix/identity/api/v1/3pid/bind$"]["POST"]
209  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
210  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
211  try {
212  LOG(INFO) << request->path;
213  std::string err;
214  bool use_json = this->JsonRequest(request);
215 
216  identt::query::Bind3pidDataT bpa;
217  if (use_json)
218  {
219  int stat = json2pb( request->content.string() , bpa.mutable_subtok() , err);
220  if (stat<0) throw SydentException("Bad Json Format",M_BAD_JSON);
221  } else {
222  form2pb( request->content.string() , bpa.mutable_subtok()); // throws on error
223  }
224  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
225 
226  // action
227  if (bpa.mutable_subtok()->sid().length()==0)
228  throw ::identt::query::SydentException("sid value required", M_MISSING_PARAMS);
229  if (bpa.mutable_subtok()->client_secret().length()==0)
230  throw ::identt::query::SydentException("client_secret value required", M_MISSING_PARAMS);
231  if (bpa.mutable_subtok()->mxid().length()==0)
232  throw ::identt::query::SydentException("mxid value required", M_MISSING_PARAMS);
233 
234  if (stptr->is_master.Get())
235  {
237  tservice.Bind3pidAction(stptr, &bpa);
238  } else {
239  identt::hrpc::HrpcClient hclient;
240  hclient.SendToMaster(stptr,::identt::hrpc::M_BIND3PID,&bpa);
241  }
242 
243  // aftermath
244  // copy the string , change this later - shreos
245  std::string output = bpa.output();
246 
247  // post to synapse endpoint
248  std::vector<std::string> splitres;
249  boost::algorithm::split(splitres, bpa.mutable_subtok()->mxid() , boost::algorithm::is_any_of(":") );
250  if (splitres.size()>=2)
251  {
252  // handle non 443 ports
253  std::string up =splitres[1];
254  for (auto i=2;i<splitres.size();++i) up += ":" + splitres[i];
255 
256  std::string url = "https://" + up + "/_matrix/federation/v1/3pid/onbind";
257  HttpClient mclient;
258  std::string ret;
259  bool status = mclient.PostJson(stptr,url,output,ret,true);
260  LOG(INFO) << "Posted to " << url << " for " << splitres[0] << " status " << status;
261  }
262 
263  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
264 
265  } catch (SydentException& e)
266  {
267  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
268  std::string output = err2json(SydentErrors.at(ecode),e.what());
269  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
270  } catch (identt::JdException& e)
271  {
272  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
273  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
274  } catch (std::exception& e)
275  {
276  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
277  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
278  } catch (...)
279  {
280  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
281  }
282  });
283  };
284  // Endpoint : GET _matrix/identity/api/v1/3pid/bind
285  helpquery->add({scope,"GET _matrix/identity/api/v1/3pid/bind", {
286  "This is the GET version of 3pid/bind",
287  "An association between a session and a Matrix user ID can be published by making a request to this.",
288  "params: sid , client_secret , mxid",
289  "where mxid takes the form @name:domain.com"
290  }
291  });
292 
293  server->resource["/_matrix/identity/api/v1/3pid/bind\\\?(.*)$"]["GET"]
294  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
295  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
296  try {
297  LOG(INFO) << request->path;
298  std::string err;
299  std::string params = request->path_match[1];
300 
301  identt::query::Bind3pidDataT bpa;
302  form2pb( params , bpa.mutable_subtok()); // throws on error
303  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
304 
305  // action
306  if (bpa.mutable_subtok()->sid().length()==0)
307  throw ::identt::query::SydentException("sid value required", M_MISSING_PARAMS);
308  if (bpa.mutable_subtok()->client_secret().length()==0)
309  throw ::identt::query::SydentException("client_secret value required", M_MISSING_PARAMS);
310  if (bpa.mutable_subtok()->mxid().length()==0)
311  throw ::identt::query::SydentException("mxid value required", M_MISSING_PARAMS);
312 
313  if (stptr->is_master.Get())
314  {
316  tservice.Bind3pidAction(stptr, &bpa);
317  } else {
318  identt::hrpc::HrpcClient hclient;
319  hclient.SendToMaster(stptr,::identt::hrpc::M_BIND3PID,&bpa);
320  }
321 
322  // aftermath
323  // copy the string , change this later - shreos
324  std::string output = bpa.output();
325 
326  // post to synapse endpoint
327  std::vector<std::string> splitres;
328  boost::algorithm::split(splitres, bpa.mutable_subtok()->mxid() , boost::algorithm::is_any_of(":") );
329  if (splitres.size()==2)
330  {
331  // handle non 443 ports
332  std::string up =splitres[1];
333  for (auto i=2;i<splitres.size();++i) up += ":" + splitres[i];
334 
335  std::string url = "https://" + up + "/_matrix/federation/v1/3pid/onbind";
336  HttpClient mclient;
337  std::string ret;
338  bool status = mclient.PostJson(stptr,url,output,ret,true);
339  LOG(INFO) << "Posted to " << url << " for " << splitres[0] << " status " << status;
340  }
341 
342  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
343  } catch (SydentException& e)
344  {
345  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
346  std::string output = err2json(SydentErrors.at(ecode),e.what());
347  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
348  } catch (identt::JdException& e)
349  {
350  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
351  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
352  } catch (std::exception& e)
353  {
354  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
355  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
356  } catch (...)
357  {
358  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
359  }
360  });
361  };
362  }
363 private:
364 
365 };
366 
367 } // namespace query
368 } // namespace identt
369 
370 #endif // _IDENTT_QUERY_THREEPID_SERVICE_HPP_
371 
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
void Bind3pidAction(::identt::utils::SharedTable::pointer stptr, ::identt::query::Bind3pidDataT *bpa)
Bind3pidAction: Bind a 3pid Request.
Definition: ThreePidService.cc:93
void GetValidated3pidAction(::identt::utils::SharedTable::pointer stptr, ::identt::query::GetValidated3pidDataT *gva)
GetValidated3pidAction: Validate a 3pid Request.
Definition: ThreePidService.cc:58
Sydent Exceptions.
Definition: SydentQuery.hpp:91
Definition: ThreePidService.hpp:44
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: HttpClient.hpp:44
Definition: BaseUtils.hpp:52
void pb2json(const google::protobuf::Message *msg, std::string &str)
pb2json : Convert protobuf to json
Definition: ProtoJson.cc:415
Definition: ThreePidService.hpp:42
Definition: ServiceBase.hpp:55
Definition: CryptoBase.hpp:49
Definition: BaseUtils.hpp:89
void form2pb(const std::string &form, google::protobuf::Message *msg)
form2pb : Convert url-encoded form to protobuf
Definition: ProtoForm.cc:129
std::string err2json(const std::string errorcode, const std::string error)
err2json : Generate a Json for Error Message
Definition: ProtoJson.cc:511
bool JsonRequest(typename HttpServerT::ReqPtr request)
JsonRequest : Check if request is json from Content-Type and Accept fields.
Definition: ServiceBase.hpp:178
Definition: HrpcClient.hpp:46
ThreePidService(identt::utils::SharedTable::pointer stptr, typename std::shared_ptr< HttpServerT > server, ::identt::query::HelpQuery::pointer helpquery, unsigned int scope)
ThreePidService : constructor.
Definition: ThreePidService.hpp:66
bool PostJson(::identt::utils::SharedTable::pointer stptr, std::string url, std::string &payload, std::string &returns, bool nothrow=false)
PostJson : send json to remote and get output.
int json2pb(const std::string &json, google::protobuf::Message *msg, std::string &err)
json2pb : Convert json to protobuf
Definition: ProtoJson.cc:446
bool SendToMaster(::identt::utils::SharedTable::pointer stptr, ::identt::hrpc::MasterCmdTypeE service_id, google::protobuf::Message *msg, bool nothrow=false)
SendToMaster : send to master and get output.