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  }