github.com/greenpau/go-authcrunch@v1.1.4/pkg/registry/user_registry_notify.go (about) 1 // Copyright 2022 Paul Greenberg greenpau@outlook.com 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package registry 16 17 import ( 18 "bytes" 19 "github.com/greenpau/go-authcrunch/pkg/credentials" 20 "github.com/greenpau/go-authcrunch/pkg/errors" 21 "github.com/greenpau/go-authcrunch/pkg/messaging" 22 "mime/quotedprintable" 23 "strings" 24 "text/template" 25 ) 26 27 // Notify serves notifications. 28 func (r *LocaUserRegistry) Notify(data map[string]string) error { 29 var requiredFields []string 30 var rcpts []string 31 32 commonRequiredFields := []string{ 33 "session_id", "request_id", "timestamp", 34 "template", 35 } 36 37 if data == nil { 38 return errors.ErrNotifyRequestDataNil 39 } 40 41 for _, fieldName := range commonRequiredFields { 42 if _, exists := data[fieldName]; !exists { 43 return errors.ErrNotifyRequestFieldNotFound.WithArgs(fieldName) 44 } 45 } 46 47 tmplName := data["template"] 48 switch tmplName { 49 case "registration_confirmation": 50 requiredFields = []string{ 51 "registration_id", "username", "email", "registration_url", 52 "registration_code", "src_ip", "src_conn_ip", 53 } 54 case "registration_ready": 55 requiredFields = []string{ 56 "registration_id", "username", "email", "registration_url", 57 "src_ip", "src_conn_ip", 58 } 59 case "registration_verdict": 60 requiredFields = []string{ 61 "username", "email", "verdict", 62 } 63 default: 64 return errors.ErrNotifyRequestTemplateUnsupported.WithArgs(tmplName) 65 } 66 67 for _, fieldName := range requiredFields { 68 if _, exists := data[fieldName]; !exists { 69 return errors.ErrNotifyRequestFieldNotFound.WithArgs(fieldName) 70 } 71 } 72 73 switch tmplName { 74 case "registration_confirmation", "registration_verdict": 75 rcpts = append(rcpts, data["email"]) 76 case "registration_ready": 77 rcpts = r.config.AdminEmails 78 } 79 80 lang := "en" 81 if v, exists := data["lang"]; exists { 82 lang = v 83 } else { 84 data["lang"] = lang 85 } 86 87 switch lang { 88 case "en": 89 default: 90 return errors.ErrNotifyRequestLangUnsupported.WithArgs(lang) 91 } 92 93 if r.config.messaging == nil { 94 return errors.ErrNotifyRequestMessagingNil.WithArgs(r.config.EmailProvider) 95 } 96 97 tmplSubj, tmplSubjErr := template.New("email_subj").Parse(messaging.EmailTemplateSubject[lang+"/"+tmplName]) 98 if tmplSubjErr != nil { 99 return errors.ErrNotifyRequestEmail.WithArgs(r.config.EmailProvider, tmplSubjErr) 100 } 101 emailSubj := bytes.NewBuffer(nil) 102 if err := tmplSubj.Execute(emailSubj, data); err != nil { 103 return errors.ErrNotifyRequestEmail.WithArgs(r.config.EmailProvider, err) 104 } 105 106 tmplBody, tmplBodyErr := template.New("email_body").Parse(messaging.EmailTemplateBody[lang+"/"+tmplName]) 107 if tmplBodyErr != nil { 108 return errors.ErrNotifyRequestEmail.WithArgs(r.config.EmailProvider, tmplBodyErr) 109 } 110 emailBody := bytes.NewBuffer(nil) 111 if err := tmplBody.Execute(emailBody, data); err != nil { 112 return errors.ErrNotifyRequestEmail.WithArgs(r.config.EmailProvider, err) 113 } 114 115 var qpEmailBody string 116 qpEmailBody, err := quotedPrintableBody(emailBody.String()) 117 if err != nil { 118 return errors.ErrNotifyRequestEmail.WithArgs(r.config.EmailProvider, err) 119 } 120 121 qpEmailSubj := emailSubj.String() 122 repl := strings.NewReplacer("\r", "", "\n", " ") 123 qpEmailSubj = strings.TrimSpace(repl.Replace(qpEmailSubj)) 124 125 providerType := r.config.messaging.GetProviderType(r.config.EmailProvider) 126 127 switch providerType { 128 case "email": 129 provider := r.config.messaging.ExtractEmailProvider(r.config.EmailProvider) 130 if provider == nil { 131 return errors.ErrNotifyRequestEmailProviderNotFound.WithArgs(r.config.EmailProvider) 132 } 133 134 providerCredName := r.config.messaging.FindProviderCredentials(r.config.EmailProvider) 135 if providerCredName == "" { 136 return errors.ErrNotifyRequestEmailProviderCredNotFound.WithArgs(r.config.EmailProvider) 137 } 138 139 var providerCred *credentials.Generic 140 if providerCredName != "passwordless" { 141 if r.config.credentials == nil { 142 return errors.ErrNotifyRequestCredNil.WithArgs(r.config.EmailProvider) 143 } 144 providerCred = r.config.credentials.ExtractGeneric(providerCredName) 145 if providerCred == nil { 146 return errors.ErrNotifyRequestCredNotFound.WithArgs(r.config.EmailProvider, providerCredName) 147 } 148 } 149 150 if err := provider.Send(&messaging.EmailProviderSendInput{ 151 Subject: qpEmailSubj, 152 Body: qpEmailBody, 153 Recipients: rcpts, 154 Credentials: providerCred, 155 }); err != nil { 156 return errors.ErrNotifyRequestEmail.WithArgs(r.config.EmailProvider, err) 157 } 158 case "file": 159 provider := r.config.messaging.ExtractFileProvider(r.config.EmailProvider) 160 if provider == nil { 161 return errors.ErrNotifyRequestEmailProviderNotFound.WithArgs(r.config.EmailProvider) 162 } 163 if err := provider.Send(&messaging.FileProviderSendInput{ 164 Subject: qpEmailSubj, 165 Body: qpEmailBody, 166 Recipients: rcpts, 167 }); err != nil { 168 return errors.ErrNotifyRequestEmail.WithArgs(r.config.EmailProvider, err) 169 } 170 default: 171 return errors.ErrNotifyRequestProviderTypeUnsupported.WithArgs(r.config.EmailProvider, providerType) 172 } 173 return nil 174 } 175 176 func quotedPrintableBody(s string) (string, error) { 177 var b bytes.Buffer 178 w := quotedprintable.NewWriter(&b) 179 if _, err := w.Write([]byte(s)); err != nil { 180 return "", err 181 } 182 if err := w.Close(); err != nil { 183 return "", err 184 } 185 return b.String(), nil 186 }