| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | #include "error_resource.hh" |
|---|
| 21 | #include "reauthn_resource.hh" |
|---|
| 22 | #include "redir_resource.hh" |
|---|
| 23 | #include "request.hh" |
|---|
| 24 | #include "templated_resource.hh" |
|---|
| 25 | #include "token.hh" |
|---|
| 26 | |
|---|
| 27 | #include "../config.hh" |
|---|
| 28 | #include "../db/db.hh" |
|---|
| 29 | #include "../db/user.hh" |
|---|
| 30 | #include "../html/util.hh" |
|---|
| 31 | #include "../msg/lexutils.hh" |
|---|
| 32 | #include "../tlate/tlate.hh" |
|---|
| 33 | #include "../smtp_client/smtp_client.hh" |
|---|
| 34 | |
|---|
| 35 | #define REQPATH "/passwd" |
|---|
| 36 | #define REQPREFIX REQPATH "/" |
|---|
| 37 | |
|---|
| 38 | namespace http |
|---|
| 39 | { |
|---|
| 40 | class passwd : public templated_resource |
|---|
| 41 | { |
|---|
| 42 | void chpass(boost::shared_ptr<request>); |
|---|
| 43 | public: |
|---|
| 44 | passwd(server::conn_cb cb) |
|---|
| 45 | : templated_resource(cb, "passwd.html") |
|---|
| 46 | {} |
|---|
| 47 | void set_attributes(boost::shared_ptr<request>, |
|---|
| 48 | tlate::data_model::ptr); |
|---|
| 49 | }; |
|---|
| 50 | |
|---|
| 51 | void passwd::chpass(boost::shared_ptr<request> req) |
|---|
| 52 | { |
|---|
| 53 | std::string (*const p)(std::string) = uri::percent_encode; |
|---|
| 54 | std::string (*const dep)(std::string) = uri::percent_decode; |
|---|
| 55 | |
|---|
| 56 | std::string uid = dep(req->get_form_field("userid")); |
|---|
| 57 | std::string pw1 = dep(req->get_form_field("password")); |
|---|
| 58 | std::string pw2 = dep(req->get_form_field("repass")); |
|---|
| 59 | std::string tokstr = dep(req->get_form_field("token")); |
|---|
| 60 | |
|---|
| 61 | boost::shared_ptr<token> &tok = cb.get_http_token(tokstr); |
|---|
| 62 | |
|---|
| 63 | boost::shared_ptr<db::user> u; |
|---|
| 64 | if (tokstr.empty()) |
|---|
| 65 | { |
|---|
| 66 | if (!req->is_authenticated()) |
|---|
| 67 | { |
|---|
| 68 | boost::shared_ptr<resource> er |
|---|
| 69 | (new reauthn_resource(cb)); |
|---|
| 70 | throw resource_exception(er); |
|---|
| 71 | } |
|---|
| 72 | u = req->get_user(); |
|---|
| 73 | if (u->get_userid() != uid) |
|---|
| 74 | { |
|---|
| 75 | boost::shared_ptr<resource> er |
|---|
| 76 | (new error_resource |
|---|
| 77 | (cb, "403 User id mismatch")); |
|---|
| 78 | throw resource_exception(er); |
|---|
| 79 | } |
|---|
| 80 | } |
|---|
| 81 | else |
|---|
| 82 | { |
|---|
| 83 | if (tok->kind != token::PASSWD) |
|---|
| 84 | { |
|---|
| 85 | boost::shared_ptr<resource> er |
|---|
| 86 | (new error_resource |
|---|
| 87 | (cb, "404 Not found")); |
|---|
| 88 | throw resource_exception(er); |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | if (tok) u = tok->get_user(); |
|---|
| 92 | if (!u) |
|---|
| 93 | { |
|---|
| 94 | boost::shared_ptr<resource> er |
|---|
| 95 | (new error_resource |
|---|
| 96 | (cb, "403 Opportunity expired")); |
|---|
| 97 | throw resource_exception(er); |
|---|
| 98 | } |
|---|
| 99 | } |
|---|
| 100 | |
|---|
| 101 | std::string err = db::user::passwd_problems(pw1); |
|---|
| 102 | |
|---|
| 103 | if (pw1 != pw2) err = "Passwords did not match."; |
|---|
| 104 | |
|---|
| 105 | if (!err.empty()) |
|---|
| 106 | { |
|---|
| 107 | boost::shared_ptr<resource> rr |
|---|
| 108 | (new redir_resource(cb, |
|---|
| 109 | "/passwd/" + |
|---|
| 110 | tokstr + |
|---|
| 111 | "?msg=" + |
|---|
| 112 | p(err), |
|---|
| 113 | "303 See other")); |
|---|
| 114 | throw resource_exception(rr); |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | u->set_password(pw1); |
|---|
| 118 | |
|---|
| 119 | if (tok) tok.reset(); |
|---|
| 120 | |
|---|
| 121 | std::string ton = u->get_display_name(); |
|---|
| 122 | std::string to = u->get_delivery_email(); |
|---|
| 123 | std::string from = |
|---|
| 124 | config["alue-name"].as<std::string>() + |
|---|
| 125 | " <" + |
|---|
| 126 | config["operator-email"].as<std::string>() + |
|---|
| 127 | ">"; |
|---|
| 128 | |
|---|
| 129 | tlate::data_model::ptr am(new tlate::data_model); |
|---|
| 130 | |
|---|
| 131 | am->insert("from", from); |
|---|
| 132 | am->insert("to", msg::make_phrase(ton) + " <" + to + ">"); |
|---|
| 133 | am->insert("userid",u->get_userid()); |
|---|
| 134 | am->insert("request_ip", req->get_peer().to_string()); |
|---|
| 135 | |
|---|
| 136 | boost::shared_ptr<tlate::tlate> tl = |
|---|
| 137 | tlate::tlate::parse("pwchanged.msg"); |
|---|
| 138 | std::ostringstream mos; |
|---|
| 139 | mos << tl->eval(am); |
|---|
| 140 | |
|---|
| 141 | std::list<std::string> recv; |
|---|
| 142 | recv.push_back(to); |
|---|
| 143 | |
|---|
| 144 | cb.smtpc().send_mail(recv, mos.str()); |
|---|
| 145 | |
|---|
| 146 | boost::shared_ptr<resource> r |
|---|
| 147 | (new templated_resource(cb, "passwd-changed.html")); |
|---|
| 148 | throw resource_exception(r); |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | void passwd::set_attributes(boost::shared_ptr<request> req, |
|---|
| 152 | tlate::data_model::ptr am) |
|---|
| 153 | { |
|---|
| 154 | std::string (*const q)(std::string,bool) = html::quote; |
|---|
| 155 | std::string (*const p)(std::string) = uri::percent_encode; |
|---|
| 156 | std::string (*const dep)(std::string) = uri::percent_decode; |
|---|
| 157 | |
|---|
| 158 | if (req->get_path().length() < sizeof REQPREFIX - 1) |
|---|
| 159 | { |
|---|
| 160 | boost::shared_ptr<resource> er |
|---|
| 161 | (new error_resource(cb, "404 Not found")); |
|---|
| 162 | throw resource_exception(er); |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | boost::shared_ptr<db::user> u; |
|---|
| 166 | if (req->get_path().length() == sizeof REQPREFIX - 1) |
|---|
| 167 | { |
|---|
| 168 | if (req->get_method() == "POST") return chpass(req); |
|---|
| 169 | if (!req->is_authenticated()) |
|---|
| 170 | { |
|---|
| 171 | boost::shared_ptr<resource> er |
|---|
| 172 | (new reauthn_resource(cb)); |
|---|
| 173 | throw resource_exception(er); |
|---|
| 174 | } |
|---|
| 175 | u = req->get_user(); |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | std::string tokstr; |
|---|
| 179 | boost::shared_ptr<token> tok; |
|---|
| 180 | if (!u) |
|---|
| 181 | { |
|---|
| 182 | tokstr = dep |
|---|
| 183 | (req->get_path().substr(sizeof REQPREFIX - 1)); |
|---|
| 184 | tok = cb.get_http_token(tokstr); |
|---|
| 185 | if (tok) u = tok->get_user(); |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | if (!u) |
|---|
| 189 | { |
|---|
| 190 | boost::shared_ptr<resource> er |
|---|
| 191 | (new error_resource |
|---|
| 192 | (cb, "410 Link expired or otherwise invalid")); |
|---|
| 193 | throw resource_exception(er); |
|---|
| 194 | } |
|---|
| 195 | |
|---|
| 196 | am->insert("userid", q(u->get_userid(), false)); |
|---|
| 197 | am->insert("username", q(u->get_display_name(), false)); |
|---|
| 198 | if (!tokstr.empty()) |
|---|
| 199 | { |
|---|
| 200 | am->insert("token", q(tokstr,false)); |
|---|
| 201 | am->insert("expiration_time", |
|---|
| 202 | q(to_iso_extended_string |
|---|
| 203 | (tok->expiration_time()), |
|---|
| 204 | false)); |
|---|
| 205 | using boost::lexical_cast; |
|---|
| 206 | using boost::posix_time::second_clock; |
|---|
| 207 | boost::posix_time::time_duration ex = |
|---|
| 208 | tok->expiration_time() - |
|---|
| 209 | second_clock::universal_time(); |
|---|
| 210 | am->insert("expires_in_hours", |
|---|
| 211 | lexical_cast<std::string>(ex.hours())); |
|---|
| 212 | am->insert("expires_in_minutes", |
|---|
| 213 | lexical_cast<std::string>(ex.minutes())); |
|---|
| 214 | am->insert("expires_in_seconds", |
|---|
| 215 | lexical_cast<std::string>(ex.seconds())); |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | am->insert("action", p(REQPREFIX)); |
|---|
| 219 | am->insert("method", "post"); |
|---|
| 220 | am->insert("enctype", "application/x-www-form-urlencoded"); |
|---|
| 221 | am->insert("accept_charlist", q("utf8",false)); |
|---|
| 222 | |
|---|
| 223 | std::string errmsg = dep(req->get_form_field("msg")); |
|---|
| 224 | if (!errmsg.empty()) |
|---|
| 225 | am->insert("errmsg", q(errmsg, false)); |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | }; |
|---|
| 229 | |
|---|
| 230 | namespace |
|---|
| 231 | { |
|---|
| 232 | class factory : public server::http_resource_factory |
|---|
| 233 | { |
|---|
| 234 | public: |
|---|
| 235 | factory() { |
|---|
| 236 | server::register_http_resource(REQPATH, this); |
|---|
| 237 | } |
|---|
| 238 | boost::shared_ptr<http::resource> operator() |
|---|
| 239 | (server::conn_cb cb, std::string) { |
|---|
| 240 | boost::shared_ptr<http::resource> rv |
|---|
| 241 | (new http::passwd(cb)); |
|---|
| 242 | return rv; |
|---|
| 243 | } |
|---|
| 244 | }; |
|---|
| 245 | factory f; |
|---|
| 246 | } |
|---|