#include <sys/wait.h>
#include <string.h>
#include <limits.h>
-#include <crypt.h>
#include <libcitadel.h>
#include "../../citadel_defs.h"
#include "../../server.h"
// The confirmation token will be generated by combining the room name and email address with the host key,
-// and then generating an encrypted hash of that string. The encrypted hash is included as part of the
-// confirmation link.
+// and then generating a one-way hash of that string. The hash is included as part of the confirmation link.
void generate_confirmation_token(char *token_buf, size_t token_buf_len, char *roomname, char *emailaddr) {
char string_to_hash[1024];
- struct crypt_data cd;
- char *ptr;
snprintf(string_to_hash, sizeof string_to_hash, "%s|%s|%s", roomname, emailaddr, CtdlGetConfigStr("host_key"));
- memset(&cd, 0, sizeof cd);
+ snprintf(token_buf, token_buf_len, "%lx", FourHash(string_to_hash, strlen(string_to_hash)));
+}
- strncpy(token_buf, crypt_r(string_to_hash, "$1$ctdl", &cd), token_buf_len);
- for (ptr=token_buf; *ptr; ++ptr) {
- if (!isalnum((char)*ptr)) *ptr='X';
- }
+// Generate a pre-authorized subscribe/unsubscribe URL for a particular email address for a particular room.
+// This can be used as the second part of a double-opt-in or double-opt-out process.
+// It can also be used to generate a "one click unsubscribe" link.
+void generate_one_click_url(char *target_buf, char *base_url, char *action, char *roomname, char *emailaddr) {
+
+ // We need a URL-safe representation of the room name
+ char encoded_roomname[ROOMNAMELEN+10];
+ urlesc(encoded_roomname, sizeof(encoded_roomname), roomname);
+
+ // The confirmation token pre-authorizes the generated URL. It is hashed by the host key so it can't be guessed.
+ char confirmation_token[128];
+ generate_confirmation_token(confirmation_token, sizeof confirmation_token, roomname, emailaddr);
+
+ // Write to the buffer
+ snprintf(target_buf, SIZ, "%s?cmd=%s&email=%s&room=%s&token=%s",
+ base_url,
+ action,
+ emailaddr,
+ encoded_roomname,
+ confirmation_token
+ );
}
// This generates an email with a link the user clicks to confirm a list subscription.
void send_subscribe_confirmation_email(char *roomname, char *emailaddr, char *url, char *confirmation_token) {
- // We need a URL-safe representation of the room name
- char urlroom[ROOMNAMELEN+10];
- urlesc(urlroom, sizeof(urlroom), roomname);
+
+ char confirm_subscribe_url[SIZ];
+ generate_one_click_url(confirm_subscribe_url, url, "confirm_subscribe", roomname, emailaddr);
char from_address[1024];
snprintf(from_address, sizeof from_address, "noreply@%s", CtdlGetConfigStr("c_fqdn"));
"<%s> to the <%s> mailing list.\n"
"\n"
"Please go here to confirm this request:\n"
- "%s?cmd=confirm_subscribe&email=%s&room=%s&token=%s\n"
+ "%s\n"
"\n"
"If this request has been submitted in error and you do not\n"
"wish to receive the <%s> mailing list, simply do nothing,\n"
"--__ctdlmultipart__\n"
"Content-type: text/html\n"
"\n"
- "<html><body><p>Someone (probably you) has submitted a request to subscribe "
- "<strong>%s</strong> to the <strong>%s</strong> mailing list.</p>"
- "<p>Please go here to confirm this request:</p>"
- "<p><a href=\"%s?cmd=confirm_subscribe&email=%s&room=%s&token=%s\">"
- "%s?cmd=confirm_subscribe&email=%s&room=%s&token=%s</a></p>"
- "<p>If this request has been submitted in error and you do not "
- "wish to receive the <strong>%s<strong> mailing list, simply do nothing, "
- "and you will not receive any further mailings.</p>"
+ "<html><body><p>Someone (probably you) has submitted a request to subscribe\n"
+ "<strong>%s</strong> to the <strong>%s</strong> mailing list.</p>\n"
+ "<p>Please go here to confirm this request:</p>\n"
+ "<p><a href=\"%s\">%s</a></p>\n"
+ "<p>If this request has been submitted in error and you do not\n"
+ "wish to receive the <strong>%s</strong> mailing list, simply do nothing,\n"
+ "and you will not receive any further mailings.</p>\n"
"</body></html>\n"
"\n"
"--__ctdlmultipart__--\n"
,
- emailaddr, roomname,
- url, emailaddr, urlroom, confirmation_token,
- roomname
- ,
- emailaddr, roomname,
- url, emailaddr, urlroom, confirmation_token,
- url, emailaddr, urlroom, confirmation_token,
- roomname
+ emailaddr, roomname, confirm_subscribe_url, roomname,
+ emailaddr, roomname, confirm_subscribe_url, confirm_subscribe_url, roomname
);
quickie_message("Citadel", from_address, emailaddr, NULL, emailtext, FMT_RFC822, "Please confirm your list subscription");
// This generates an email with a link the user clicks to confirm a list unsubscription.
void send_unsubscribe_confirmation_email(char *roomname, char *emailaddr, char *url, char *confirmation_token) {
- // We need a URL-safe representation of the room name
- char urlroom[ROOMNAMELEN+10];
- urlesc(urlroom, sizeof(urlroom), roomname);
+
+ char confirm_unsubscribe_url[SIZ];
+ generate_one_click_url(confirm_unsubscribe_url, url, "confirm_unsubscribe", roomname, emailaddr);
char from_address[1024];
snprintf(from_address, sizeof from_address, "noreply@%s", CtdlGetConfigStr("c_fqdn"));
"<%s> from the <%s> mailing list.\n"
"\n"
"Please go here to confirm this request:\n"
- "%s?cmd=confirm_unsubscribe&email=%s&room=%s&token=%s\n"
+ "%s\n"
"\n"
"If this request has been submitted in error and you still\n"
"wish to receive the <%s> mailing list, simply do nothing,\n"
"--__ctdlmultipart__\n"
"Content-type: text/html\n"
"\n"
- "<html><body><p>Someone (probably you) has submitted a request to unsubscribe "
- "<strong>%s</strong> from the <strong>%s</strong> mailing list.</p>"
- "<p>Please go here to confirm this request:</p>"
- "<p><a href=\"%s?cmd=confirm_unsubscribe&email=%s&room=%s&token=%s\">"
- "%s?cmd=confirm_unsubscribe&email=%s&room=%s&token=%s</a></p>"
- "<p>If this request has been submitted in error and you still "
- "wish to receive the <strong>%s<strong> mailing list, simply do nothing, "
- "and you will remain subscribed.</p>"
+ "<html><body><p>Someone (probably you) has submitted a request to unsubscribe\n"
+ "<strong>%s</strong> from the <strong>%s</strong> mailing list.</p>\n"
+ "<p>Please go here to confirm this request:</p>\n"
+ "<p><a href=\"%s\">%s</a></p>\n"
+ "<p>If this request has been submitted in error and you still\n"
+ "wish to receive the <strong>%s</strong> mailing list, simply do nothing,\n"
+ "and you will remain subscribed.</p>\n"
"</body></html>\n"
"\n"
"--__ctdlmultipart__--\n"
,
- emailaddr, roomname,
- url, emailaddr, urlroom, confirmation_token,
- roomname
- ,
- emailaddr, roomname,
- url, emailaddr, urlroom, confirmation_token,
- url, emailaddr, urlroom, confirmation_token,
- roomname
+ emailaddr, roomname, confirm_unsubscribe_url, roomname,
+ emailaddr, roomname, confirm_unsubscribe_url, confirm_unsubscribe_url, roomname
);
quickie_message("Citadel", from_address, emailaddr, NULL, emailtext, FMT_RFC822, "Please confirm your list unsubscription");