identt
ValidateService.hpp
Go to the documentation of this file.
1 
33 #ifndef _IDENTT_QUERY_VALIDATE_SERVICE_HPP_
34 #define _IDENTT_QUERY_VALIDATE_SERVICE_HPP_
35 
36 #include <query/QueryBase.hpp>
38 #include <hrpc/HrpcClient.hpp>
39 
40 #ifndef IDENTT_SEND_SMS_REQUEST_TOKEN
41 #define IDENTT_SEND_SMS_REQUEST_TOKEN
42 #endif
43 
44 namespace identt {
45 namespace query {
46 
47 template <class HttpServerT>
48 class ValidateService : public identt::query::ServiceBase<HttpServerT> {
49 public:
50 
72  identt::utils::SharedTable::pointer stptr,
73  typename std::shared_ptr<HttpServerT> server,
74  ::identt::query::HelpQuery::pointer helpquery,
75  unsigned int scope)
76  : identt::query::ServiceBase<HttpServerT>(IDENTT_SERVICE_SCOPE_HTTP | IDENTT_SERVICE_SCOPE_HTTPS)
77  {
78  if (!(this->myscope & scope)) return; // scope mismatch
79 
80  // Endpoint : POST _matrix/identity/api/v1/validate/{service:string}/requestToken
81 
82  helpquery->add({scope,"POST _matrix/identity/api/v1/validate/{service:string}/requestToken", {
83  "service can be email or msisdn ",
84  "params : email , client_secret , send_attempt, next_link",
85  "params : phone_number, country , client_secret , send_attempt, next_link",
86  "This will create a new session on the identity service, identified by an sid.",
87  "It may also optionally specify next_link to redirect on successful validation.",
88  "The identity service will send an email/sms containing a token to verify.",
89  "We return the sid generated for this session to the caller.",
90  "If a send_attempt is specified, the server will only send an request if the ",
91  "send_attempt is a number greater than the most recent one which it has seen",
92  "Note that Home Servers offer APIs that proxy this API"
93  }
94  });
95 
96  server->resource["/_matrix/identity/api/v1/validate/(email|msisdn)/requestToken$"]["POST"]
97  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
98  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
99  try {
100  LOG(INFO) << request->path;
101  std::string err;
102  identt::query::RequestTokenDataT rtoka;
103  rtoka.set_medium ( request->path_match[1] );
104  bool use_json = this->JsonRequest(request);
105 
106  if (use_json)
107  {
108  int stat = json2pb( request->content.string() , rtoka.mutable_reqtok() , err);
109  if (stat<0) throw SydentException("Bad Json Format",M_BAD_JSON);
110  } else {
111  form2pb( request->content.string() , rtoka.mutable_reqtok()); // throws on error
112  }
113  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
114 
115  DLOG(INFO) << rtoka.DebugString();
116  // action
117  if (stptr->is_master.Get())
118  {
120  valservice.RequestTokenAction(stptr, &rtoka);
121  } else {
122  identt::hrpc::HrpcClient hclient;
123  hclient.SendToMaster(stptr,::identt::hrpc::M_REQUESTTOKEN,&rtoka);
124  }
125 
126  IDENTT_SEND_SMS_REQUEST_TOKEN
127 
128  LOG(INFO)
129  << "phone_number=\"" << rtoka.mutable_reqtok()->phone_number() << "\""
130  << " token=\"" << rtoka.token()
131  << "\" sid=\"" << rtoka.mutable_ssid()->sid() << "\"";
132 
133  // aftermath
134  std::string output;
135  pb2json(rtoka.mutable_ssid() , output);
136  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
137  } catch (SydentException& e)
138  {
139  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
140  std::string output = err2json(SydentErrors.at(ecode),e.what());
141  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
142  } catch (identt::JdException& e)
143  {
144  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
145  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
146  } catch (std::exception& e)
147  {
148  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
149  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
150  } catch (...)
151  {
152  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
153  }
154  });
155  };
156 
157  // Endpoint : GET _matrix/identity/api/v1/validate/{service:string}/requestToken
158 
159  helpquery->add({scope, "GET _matrix/identity/api/v1/validate/{service:string}/requestToken?{params}", {
160  "service can be email or msisdn ",
161  "params : email , client_secret , send_attempt, next_link",
162  "params : phone_number, country , client_secret , send_attempt, next_link",
163  "This is the GET version of requestToken"
164  "Note that Home Servers offer APIs that proxy this API"
165  }
166  });
167 
168  server->resource["/_matrix/identity/api/v1/validate/(email|msisdn)/requestToken\\\?(.*)$"]["GET"]
169  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
170  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
171  try {
172  LOG(INFO) << request->path;
173  std::string err;
174  identt::query::RequestTokenDataT rtoka;
175  rtoka.set_medium ( request->path_match[1] );
176 
177  std::string params = request->path_match[2];
178  form2pb( params , rtoka.mutable_reqtok()); // throws on error
179 
180  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
181 
182  DLOG(INFO) << rtoka.DebugString();
183 
184  // action
185  if (stptr->is_master.Get())
186  {
188  valservice.RequestTokenAction(stptr, &rtoka);
189  } else {
190  identt::hrpc::HrpcClient hclient;
191  hclient.SendToMaster(stptr,::identt::hrpc::M_REQUESTTOKEN,&rtoka);
192  }
193 
194  IDENTT_SEND_SMS_REQUEST_TOKEN
195 
196  LOG(INFO) << "token=\"" << rtoka.token() << "\" sid=\"" << rtoka.ssid().sid() << "\"";
197 
198  // aftermath
199  std::string output;
200  pb2json(rtoka.mutable_ssid() , output);
201  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
202  } catch (SydentException& e)
203  {
204  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
205  std::string output = err2json(SydentErrors.at(ecode),e.what());
206  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
207  } catch (identt::JdException& e)
208  {
209  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
210  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
211  } catch (std::exception& e)
212  {
213  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
214  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
215  } catch (...)
216  {
217  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
218  }
219  });
220  };
221 
222  // Endpoint : POST _matrix/identity/api/v1/validate/{service:string}/submitToken
223 
224  helpquery->add({scope,"POST _matrix/identity/api/v1/validate/{service:string}/submitToken", {
225  "service can be email or msisdn ",
226  "A user may make a POST request with the following parameters",
227  "sid: the sid for the session, generated by the requestToken call.",
228  "client_secret: the client secret which was supplied to the requestToken call.",
229  "token: the token generated by the requestToken call, and emailed to the user.",
230  "If these three values are consistent with a set generated by a requestToken call,",
231  "ownership of the email address is considered to have been validated.",
232  "Note that Home Servers offer APIs that proxy this API"
233  }
234  });
235 
236  server->resource["/_matrix/identity/api/v1/validate/(email|msisdn)/submitToken$"]["POST"]
237  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
238  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
239  try {
240  LOG(INFO) << request->path;
241  std::string err;
242  identt::query::SubmitTokenDataT stoka;
243  stoka.set_medium ( request->path_match[1] );
244  bool use_json = this->JsonRequest(request);
245 
246  if (use_json)
247  {
248  int stat = json2pb( request->content.string() , stoka.mutable_subtok() , err);
249  if (stat<0) throw SydentException("Bad Json Format",M_BAD_JSON);
250  } else {
251  form2pb( request->content.string() , stoka.mutable_subtok()); // throws on error
252  }
253  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
254 
255  // action
256  if (stptr->is_master.Get())
257  {
259  valservice.SubmitTokenAction(stptr, &stoka);
260  } else {
261  identt::hrpc::HrpcClient hclient;
262  hclient.SendToMaster(stptr,::identt::hrpc::M_SUBMITTOKEN,&stoka);
263  }
264 
265  // aftermath
266  std::string output;
267  pb2json(stoka.mutable_result() , output);
268  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
269  } catch (SydentException& e)
270  {
271  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
272  std::string output = err2json(SydentErrors.at(ecode),e.what());
273  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
274  } catch (identt::JdException& 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 (std::exception& e)
279  {
280  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
281  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
282  } catch (...)
283  {
284  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
285  }
286  });
287  };
288 
289  // Endpoint : GET _matrix/identity/api/v1/validate/{service:string}/submitToken
290 
291  helpquery->add({scope,"GET _matrix/identity/api/v1/validate/{service:string}/submitToken?{params}", {
292  "service can be email or msisdn ",
293  "params : sid , client_secret , token ",
294  "This is the GET version of submitToken"
295  "Note that Home Servers offer APIs that proxy this API"
296  }
297  });
298 
299  server->resource["/_matrix/identity/api/v1/validate/(email|msisdn)/submitToken\\\?(.*)$"]["GET"]
300  =[this,stptr](typename HttpServerT::RespPtr response, typename HttpServerT::ReqPtr request) {
301  IDENTT_PARALLEL_ONE([this,stptr,response,request] {
302  try {
303  LOG(INFO) << request->path;
304  std::string err;
305  identt::query::SubmitTokenDataT stoka;
306  stoka.set_medium ( request->path_match[1] );
307  std::string params = request->path_match[2];
308 
309  form2pb( params , stoka.mutable_subtok()); // throws on error
310  if (!stptr->is_ready.Get()) throw identt::BadDataException("System Not Ready");
311 
312  // action
313  if (stptr->is_master.Get())
314  {
316  valservice.SubmitTokenAction(stptr, &stoka);
317  } else {
318  identt::hrpc::HrpcClient hclient;
319  hclient.SendToMaster(stptr,::identt::hrpc::M_SUBMITTOKEN,&stoka);
320  }
321 
322  // aftermath
323  std::string output;
324  pb2json(stoka.mutable_result() , output);
325  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
326  } catch (SydentException& e)
327  {
328  int ecode = (e.ecode()>=IDENTT_SYDENT_ERROR_MIN && e.ecode()<=IDENTT_SYDENT_ERROR_MAX) ? e.ecode() : M_UNKNOWN;
329  std::string output = err2json(SydentErrors.at(ecode),e.what());
330  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
331  } catch (identt::JdException& e)
332  {
333  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
334  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
335  } catch (std::exception& e)
336  {
337  std::string output = err2json(SydentErrors.at(M_UNKNOWN),e.what());
338  this->HttpOKAction(response,request,200,"OK","application/json",output,true);
339  } catch (...)
340  {
341  this->HttpErrorAction(response,request,500,"INTERNAL SERVER ERROR");
342  }
343  });
344  };
345  }
346 
347 private:
348 
349 };
350 } // namespace query
351 } // namespace identt
352 
353 #endif // _IDENTT_QUERY_VALIDATE_SERVICE_HPP_
354 
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
Definition: ValidateService.hpp:42
Definition: ValidateService.hpp:48
Sydent Exceptions.
Definition: SydentQuery.hpp:91
void SubmitTokenAction(::identt::utils::SharedTable::pointer stptr, ::identt::query::SubmitTokenDataT *stoka)
SubmitTokenAction : Service Endpoint SubmitToken.
Definition: ValidateService.cc:154
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
void pb2json(const google::protobuf::Message *msg, std::string &str)
pb2json : Convert protobuf to json
Definition: ProtoJson.cc:415
Definition: ServiceBase.hpp:55
Definition: CryptoBase.hpp:49
Definition: BaseUtils.hpp:89
void RequestTokenAction(::identt::utils::SharedTable::pointer stptr, ::identt::query::RequestTokenDataT *rtoka)
RequestTokenAction : Service Endpoint RequestToken.
Definition: ValidateService.cc:47
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
ValidateService(identt::utils::SharedTable::pointer stptr, typename std::shared_ptr< HttpServerT > server, ::identt::query::HelpQuery::pointer helpquery, unsigned int scope)
ValidateService : constructor.
Definition: ValidateService.hpp:71
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.