github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/model/instance/lifecycle/magic_link.go (about) 1 package lifecycle 2 3 import ( 4 "errors" 5 "net/url" 6 7 "github.com/cozy/cozy-stack/model/instance" 8 csettings "github.com/cozy/cozy-stack/model/settings" 9 "github.com/cozy/cozy-stack/pkg/crypto" 10 "github.com/cozy/cozy-stack/pkg/emailer" 11 ) 12 13 // ErrMagicLinkNotAvailable is used when requesting a magic link on a Cozy 14 // where this feature has not been activated. 15 var ErrMagicLinkNotAvailable = errors.New("magic link is not available on this instance") 16 17 // ErrInvalidMagicLink is used when the code for a magic link is invalid 18 var ErrInvalidMagicLink = errors.New("invalid magic link") 19 20 func SendMagicLink(inst *instance.Instance, redirect string) error { 21 code, err := CreateMagicLinkCode(inst) 22 if err != nil { 23 return err 24 } 25 26 link := inst.PageURL("/auth/magic_link", url.Values{ 27 "code": []string{code}, 28 "redirect": []string{redirect}, 29 }) 30 publicName, _ := csettings.PublicName(inst) 31 return emailer.SendEmail(inst, &emailer.TransactionalEmailCmd{ 32 TemplateName: "magic_link", 33 TemplateValues: map[string]interface{}{ 34 "MagicLink": link, 35 "PublicName": publicName, 36 }, 37 }) 38 } 39 40 func CreateMagicLinkCode(inst *instance.Instance) (string, error) { 41 if !inst.MagicLink { 42 return "", ErrMagicLinkNotAvailable 43 } 44 45 code := crypto.GenerateRandomString(instance.MagicLinkCodeLen) 46 if err := GetStore().SaveMagicLinkCode(inst, code); err != nil { 47 return "", err 48 } 49 return code, nil 50 } 51 52 func CheckMagicLink(inst *instance.Instance, code string) error { 53 if !GetStore().CheckMagicLinkCode(inst, code) { 54 return ErrInvalidMagicLink 55 } 56 return nil 57 }