/// <summary> /// Checks out preconfirmed email table to see if a user has already opted in. /// This way they wont have to opt-in twice if they resubscribe later. /// It also prevents us from knowing too much about our users - we can't reverse this hash and we don't store unsubscribed emails. /// </summary> /// <param name="email"></param> /// <returns></returns> public async Task <bool> CheckIsPreconfirmed(string email) { await FirestoreSetup(); try { string hashed = EncryptorService.OneWayHash(email.ToLowerInvariant()); hashed = EncryptorService.Base64Encode(hashed); DocumentReference doc = DBHandle.Collection(PRECONFIRMED).Document(hashed); DocumentSnapshot ds = await doc.GetSnapshotAsync(); return(ds.Exists); } catch (Exception e) { Logger.Log($"Some error ocurred while checking if the supplied email was preconfirmed: {e.Message}"); return(false); } }
/// <summary> /// A user can request to be expunged from the system. /// </summary> /// <param name="email"></param> /// <returns></returns> public async Task GDPRDelete(string email) { await FirestoreSetup(); try { string hashed = EncryptorService.OneWayHash(email.ToLowerInvariant()); hashed = EncryptorService.Base64Encode(hashed); DocumentReference doc = DBHandle.Collection(PRECONFIRMED).Document(hashed); await DBHandle.RunTransactionAsync(async transaction => { transaction.Delete(doc); }); } catch (Exception e) { Logger.Log($"Some error ocurred while deleteing a preconfirmed hash: {e.Message}"); } }
public MailgunEmail MakeEmail(Subscriber s, List <LambdaMatch> lms) { // remember to include an Unsubscribe Link int itemCount = lms.Sum(x => x.Posts.Count); string subjectSingle = "1 new item that matched your criteria has been posted"; string subjectPlural = $"{itemCount} new items that matched your critiera have been posted"; MailgunEmail m = new MailgunEmail() { From = POSTMASTER, To = { s.DocumentId }, Subject = itemCount == 1 ? subjectSingle : subjectPlural }; string body = (itemCount == 1 ? subjectSingle : subjectPlural) + "\n\n"; string BSTtoSTring(BST bst) { switch (bst) { case BST.BST: return("buy, sell, or trade"); case BST.BUY: return("buy"); case BST.SELL: return("sell"); case BST.TRADE: return("trade"); case BST.NONE: return("none"); } return(""); } foreach (LambdaMatch lm in lms) { // Assemble Subheader string WTStr = $"People looking to {BSTtoSTring(lm.FbMatch.BST)}"; string fromStr = "products from " + (lm.FbMatch.Companies.Any() ? $"companies [{String.Join(", ", lm.FbMatch.Companies)}]" : "any company"); Currency c = CurrencyMap.CurrencyDict[lm.FbMatch.Currency]; string priceStr = lm.FbMatch.Price.HasValue ? $"for {(lm.FbMatch.BST == BST.BUY ? "more than or equal to " : "less than or equal to")} " + $"{c.symbol}{lm.FbMatch.Price.Value} {c.Code}" : "at any price"; string matchBody = $"{WTStr} {fromStr} {priceStr}:\n"; // Assemble Items foreach (BSTComment comment in lm.Posts) { string seller = comment.Seller; string comp = comment.Company; string product = comment.Product == "?" ? "<product unknown>" : comment.Product; string url = comment.Url; Currency c2 = CurrencyMap.CurrencyDict[comment.Currency]; string pstr = comment.Price == 0 ? "<price not posted>" : $"{c2.symbol}{comment.Price} {c2.Code}"; string commentStr = $"{comp} {product} by {seller} for {pstr}\n{url}\n\n"; matchBody += commentStr; } body += matchBody; } // make unsubscribe link string encryptionKey = Environment.GetEnvironmentVariable("ESK8BST_ENCRYPTION_KEY"); string encryptedPayload = EncryptorService.Base64Encode(s.DocumentId); //AESThenHMAC.SimpleEncryptWithPassword(s.DocumentId.ToLower(), encryptionKey); string link = $"https://1lol87xzbj.execute-api.us-east-2.amazonaws.com/Prod/unsubscribe?confirmkey={encryptedPayload}"; string unsubtext = $"Unsubscribe: {link}"; body += $"\n\n\n\n {unsubtext}"; m.Body = body; return(m); }