2018-12-25 19:22:13 +00:00
package scsusers
import (
"bytes"
2020-06-04 20:02:46 +00:00
"crypto/rand"
2018-12-25 19:22:13 +00:00
"database/sql"
2020-06-04 20:02:46 +00:00
"encoding/base32"
"encoding/json"
2018-12-25 19:22:13 +00:00
"fmt"
"html/template"
"log"
"net/smtp"
"strings"
2020-08-22 00:16:17 +00:00
"time"
2020-12-19 01:41:28 +00:00
"github.com/jmoiron/sqlx"
"golang.org/x/crypto/bcrypt"
2020-06-04 20:02:46 +00:00
)
2018-12-27 21:49:59 +00:00
2018-12-25 19:22:13 +00:00
type templates struct {
Registration * template . Template
Alert * template . Template
Recovery * template . Template
}
type config struct {
SiteName string
FromEmail string
Templates templates
2020-06-04 20:02:46 +00:00
SMTPServer string
2018-12-25 19:22:13 +00:00
db * sqlx . DB
2023-09-19 22:01:41 +00:00
testing bool
2018-12-25 19:22:13 +00:00
TablePrefix string
}
2018-12-28 19:33:36 +00:00
type UserData struct {
2023-09-19 22:01:41 +00:00
UserID int64 ` db:"id" `
Username string ` db:"username" `
Password string ` db:"password" `
Meta map [ string ] metadata
}
type metadata struct {
Key string ` db:"meta_key" `
Value string ` db:"meta_value" `
ID int64 ` db:"id" `
2018-12-28 19:33:36 +00:00
}
2018-12-25 19:22:13 +00:00
var c config
2019-01-02 19:04:40 +00:00
func Init ( dbin * sqlx . DB , tp , sitename , fromaddr , smtpserver string ) {
2018-12-25 19:22:13 +00:00
c . db = dbin
c . TablePrefix = tp
c . SiteName = sitename
c . FromEmail = fromaddr
2020-06-04 20:02:46 +00:00
c . SMTPServer = smtpserver
2018-12-25 19:22:13 +00:00
SetRegistrationTemplate ( "" )
SetAlertTemplate ( "" )
SetRecoveryTemplate ( "" )
}
func UsernameAvailable ( username string ) bool {
2020-06-04 20:02:46 +00:00
if len ( username ) == 0 {
2018-12-28 19:33:36 +00:00
return false
}
2020-07-18 11:55:19 +00:00
var tmp string
2020-07-18 12:03:31 +00:00
username = strings . ToLower ( username )
2020-07-18 11:55:19 +00:00
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( "select username from %s_auth where username = ?" , c . TablePrefix )
2020-07-18 12:03:31 +00:00
err := c . db . Get ( & tmp , q , username )
2018-12-25 19:22:13 +00:00
if err == sql . ErrNoRows {
return true
}
2018-12-27 22:09:23 +00:00
if err != nil {
log . Printf ( "UsernameAvailable returned error: " + err . Error ( ) + " Query was " + q )
return false
}
2018-12-25 19:22:13 +00:00
return false
}
/* Check for username availability, add to database, send email */
func Register ( username , email , ip string ) bool {
if ! UsernameAvailable ( username ) {
return false
}
2020-07-18 12:03:31 +00:00
username = strings . ToLower ( username )
2020-07-18 11:55:19 +00:00
2018-12-25 19:22:13 +00:00
pass := randBytes ( 16 )
2018-12-27 22:09:23 +00:00
crypt , err := bcrypt . GenerateFromPassword ( pass , 10 )
2018-12-25 19:22:13 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.Register: Bcrypt GenerateFromPassword failed? Pass is %s and error is %s\n" , pass , err . Error ( ) )
2018-12-25 19:22:13 +00:00
return false
}
2023-09-19 22:09:33 +00:00
_ , err = c . db . Query ( fmt . Sprintf ( "insert into %s_auth (username, password) VALUES (?,?)" , c . TablePrefix ) , username , crypt )
2018-12-25 19:22:13 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.Register: insert failed: %s\n" , err . Error ( ) )
2018-12-25 19:22:13 +00:00
return false
}
2023-09-19 22:01:41 +00:00
if c . testing {
return true
}
2020-07-23 22:12:44 +00:00
if SendRegistrationEmail ( email , username , string ( pass ) ) {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.Register: New user registration: %s from %s\n" , username , ip )
2018-12-27 22:09:23 +00:00
return true
}
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.Register: Failed to send registration email, deleting user %s\n" , username )
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( "delete from %s_auth where username = ? AND password=?" , c . TablePrefix )
2020-07-18 12:03:31 +00:00
_ , err = c . db . Exec ( q , username , string ( crypt ) )
2018-12-27 22:09:23 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.Register: Failed to delete new user %s: %s\n" , username , err . Error ( ) )
2018-12-27 22:09:23 +00:00
}
return false
2018-12-25 19:22:13 +00:00
}
2023-09-19 22:01:41 +00:00
func NewUser ( ) * UserData {
var u UserData
u . Meta = make ( map [ string ] metadata )
return & u
}
func Get ( username string ) ( * UserData , bool ) {
2020-07-18 11:55:19 +00:00
2023-09-19 22:01:41 +00:00
u := NewUser ( )
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( "select username, password, id from %s_auth where username=?" , c . TablePrefix )
2023-09-19 22:12:55 +00:00
err := c . db . Get ( u , q , username )
2018-12-27 21:49:59 +00:00
if err != nil {
2023-09-19 22:01:41 +00:00
if err == sql . ErrNoRows {
return nil , false
}
log . Printf ( "scsusers.Get: %s" , err . Error ( ) )
return nil , false
}
2023-09-19 22:15:53 +00:00
q = fmt . Sprintf ( "select meta_key, meta_value, id from %s_meta where user=%d" , c . TablePrefix , u . UserID )
2023-09-19 22:01:41 +00:00
err = c . db . Select ( & u . Meta , q )
if err != nil && err != sql . ErrNoRows {
log . Printf ( "scsuser.Get: select: %s" , err . Error ( ) )
}
return u , true
}
func Login ( username , password string ) bool {
u , ok := Get ( username )
if ! ok {
2018-12-27 21:49:59 +00:00
return false
}
2023-09-19 22:01:41 +00:00
if bcrypt . CompareHashAndPassword ( [ ] byte ( u . Password ) , [ ] byte ( password ) ) != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.Login: Failed password for " + username )
2018-12-27 21:49:59 +00:00
return false
}
2019-01-24 13:15:54 +00:00
log . Printf ( "User %s logged in\n" , username )
2018-12-28 19:33:36 +00:00
return true
}
2023-09-19 22:01:41 +00:00
func ( u * UserData ) ChangePassword ( oldpass , newpass string ) bool {
if bcrypt . CompareHashAndPassword ( [ ] byte ( u . Password ) , [ ] byte ( oldpass ) ) != nil {
log . Printf ( "scsusers.ChangePassword: Failed password for %s\n" , u . Username )
2019-01-02 15:21:05 +00:00
return false
}
2023-09-19 22:01:41 +00:00
newcrypt , err := bcrypt . GenerateFromPassword ( [ ] byte ( newpass ) , 10 )
if err != nil {
log . Printf ( "scsusers.ChangePassword: generate: %s" , err . Error ( ) )
2019-01-02 15:21:05 +00:00
return false
}
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( "update %s_auth set password=? where userid=?" , c . TablePrefix )
_ , err = c . db . Exec ( q , newcrypt , u . UserID )
2020-06-04 20:02:46 +00:00
if err != nil {
2023-09-19 22:01:41 +00:00
log . Printf ( "scsusers.ChangePassword: update failed for %s: %s\n" , u . Username , err . Error ( ) )
2019-01-02 15:21:05 +00:00
return false
}
return true
2020-06-04 20:02:46 +00:00
2019-01-02 15:21:05 +00:00
}
2019-01-11 21:39:47 +00:00
func GetUserid ( username string ) int64 {
var i int64
2020-07-18 12:03:31 +00:00
username = strings . ToLower ( username )
2020-07-18 11:55:19 +00:00
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( "select userid from %s_auth where username = ?" , c . TablePrefix )
2020-07-18 12:03:31 +00:00
err := c . db . Get ( & i , q , username )
2019-01-11 21:39:47 +00:00
if err != nil {
log . Printf ( "scsusers.getUserId: Error loading user: %s : %s\n" , username , err . Error ( ) )
return 0
}
return i
}
2020-07-18 11:55:19 +00:00
2023-09-19 22:01:41 +00:00
func ( u * UserData ) Get ( key string ) ( string , bool ) {
tmp , ok := u . Meta [ key ]
return tmp . Value , ok
}
func ( u * UserData ) Set ( key , value string ) error {
tmp , ok := u . Meta [ key ]
if ok {
2023-09-19 22:09:33 +00:00
_ , err := c . db . Query ( fmt . Sprintf ( "delete from %s_meta where id=?" , c . TablePrefix ) , tmp . ID )
2023-09-19 22:01:41 +00:00
if err != nil {
log . Printf ( "scsauth: set: delete: %s" , err . Error ( ) )
return err
}
2018-12-28 19:33:36 +00:00
}
2023-09-19 22:01:41 +00:00
var insertid int64
2023-09-19 22:09:33 +00:00
err := c . db . Get ( & insertid , fmt . Sprintf ( "insert into %s_meta (userid, meta_key, meta_value) VALUES (?,?,?) returning id" , c . TablePrefix ) , u . UserID , key , value )
2018-12-28 19:33:36 +00:00
if err != nil {
2023-09-19 22:01:41 +00:00
log . Printf ( "scsauth: set: insert: %s" , err . Error ( ) )
return err
2018-12-28 19:33:36 +00:00
}
2023-09-19 22:01:41 +00:00
var m metadata
m . Key = key
m . Value = value
m . ID = insertid
u . Meta [ key ] = m
return nil
2018-12-28 19:33:36 +00:00
}
func SaveUser ( username string , d UserData ) bool {
2020-07-18 12:03:31 +00:00
username = strings . ToLower ( username )
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( "update %s_userdata set data=? where username = ?" , c . TablePrefix )
2020-06-04 20:02:46 +00:00
j , err := json . Marshal ( d )
2018-12-28 19:33:36 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.SaveUser: json.Marshal failed for username %s : %s\n" , username , err . Error ( ) )
2018-12-28 19:33:36 +00:00
return false
}
2020-07-18 12:03:31 +00:00
_ , err = c . db . Exec ( q , username , j )
2018-12-28 19:33:36 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.SaveUser: db.Exec failed for username %s : %s\n" , username , err . Error ( ) )
2018-12-28 19:33:36 +00:00
return false
}
2018-12-27 21:49:59 +00:00
return true
}
2019-07-23 23:34:54 +00:00
type Metadata struct {
2020-07-18 11:55:19 +00:00
MetaKey string ` db:"meta_key" `
MetaValue string ` db:"meta_value" `
2019-07-23 23:34:54 +00:00
}
2020-06-04 20:02:46 +00:00
func GetAllMeta ( username string ) map [ string ] string {
meta := make ( map [ string ] string )
2020-07-18 12:03:31 +00:00
username = strings . ToLower ( username )
2020-07-18 11:55:19 +00:00
2020-06-04 20:02:46 +00:00
q := fmt . Sprintf ( ` select meta_key , meta_value
2019-07-23 23:34:54 +00:00
from % s_user_metadata where
2023-09-19 22:09:33 +00:00
user_id = ( select userid from % s_auth where username = ? ) ` ,
2020-06-04 20:02:46 +00:00
c . TablePrefix , c . TablePrefix )
2020-07-18 12:03:31 +00:00
rows , err := c . db . Queryx ( q , username )
2020-06-04 20:02:46 +00:00
if err != nil && err != sql . ErrNoRows {
2019-07-23 23:34:54 +00:00
log . Printf ( "scsusers.GetAllMeta: %s: %s\n" , username , err . Error ( ) )
return meta
}
2020-06-04 20:02:46 +00:00
var m Metadata
2019-07-23 23:34:54 +00:00
for rows . Next ( ) {
2020-06-04 20:02:46 +00:00
err = rows . StructScan ( & m )
2019-07-23 23:34:54 +00:00
if err != nil {
2020-07-18 11:55:19 +00:00
log . Printf ( "scsusers.GetAllMeta: StructScan: %s: %s\n" , username , err . Error ( ) )
2019-07-23 23:34:54 +00:00
return meta
}
2020-06-04 20:02:46 +00:00
meta [ m . MetaKey ] = m . MetaValue
2019-07-23 23:34:54 +00:00
}
return meta
}
func GetMeta ( username string , metakey string ) string {
var v string
2020-07-18 12:03:31 +00:00
username = strings . ToLower ( username )
2020-07-18 11:55:19 +00:00
2020-06-04 20:02:46 +00:00
q := fmt . Sprintf ( ` select meta_value from % s_user_metadata where
2023-09-19 22:09:33 +00:00
user_id = ( select userid from % s_auth where username = ? ) AND meta_key = ? ` , c . TablePrefix , c . TablePrefix )
2020-07-18 12:03:31 +00:00
err := c . db . Get ( & v , q , username , metakey )
2020-06-04 20:02:46 +00:00
if err != nil && err != sql . ErrNoRows {
2019-07-23 23:34:54 +00:00
log . Printf ( "scsusers.GetMeta: %s - %s - %s\n" , username , metakey , err . Error ( ) )
}
2020-06-04 20:02:46 +00:00
if v == "" {
// get default user
err := c . db . Get ( & v , q , "//default//" , metakey )
if err != nil && err != sql . ErrNoRows {
2019-07-25 22:23:20 +00:00
log . Printf ( "scsusers.GetMeta: %s - %s - %s\n" , username , metakey , err . Error ( ) )
}
2020-06-04 20:02:46 +00:00
2019-07-25 22:23:20 +00:00
}
2019-07-23 23:34:54 +00:00
return v
}
func SetMeta ( username string , metakey string , metavalue string ) {
var err error
2020-07-18 12:03:31 +00:00
username = strings . ToLower ( username )
2020-07-18 11:55:19 +00:00
2020-06-04 20:02:46 +00:00
if metavalue == "" {
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( ` delete from %s_user_metadata where user_id=(select userid from %s_auth where username = ?) AND meta_key=? ` ,
2019-07-23 23:34:54 +00:00
c . TablePrefix , c . TablePrefix )
2020-07-18 12:03:31 +00:00
_ , err = c . db . Exec ( q , username , metakey )
2019-07-23 23:34:54 +00:00
} else {
2020-06-04 20:02:46 +00:00
q := fmt . Sprintf ( ` insert into % s_user_metadata ( user_id , meta_key , meta_value ) VALUES
2023-09-19 22:09:33 +00:00
( ( select userid from % s_auth where username = ? ) , ? , ? ) ` , c . TablePrefix , c . TablePrefix )
2020-07-18 12:03:31 +00:00
_ , err = c . db . Exec ( q , username , metakey , metavalue )
2019-07-23 23:34:54 +00:00
}
if err != nil {
log . Printf ( "scsusers.SetMeta: %s %s %s %s\n" , username , metakey , metavalue , err . Error ( ) )
}
}
2020-07-18 11:55:19 +00:00
func RecoverByUsername ( username string ) {
var email string
2020-07-18 12:03:31 +00:00
username = strings . ToLower ( username )
2020-07-18 11:55:19 +00:00
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( "select email from %s_auth where username = ?" , c . TablePrefix )
2020-07-18 12:03:31 +00:00
err := c . db . Get ( & email , q , username )
2020-06-04 20:02:46 +00:00
if err != sql . ErrNoRows {
recoverycode := randBytes ( 16 )
2023-09-19 22:09:33 +00:00
qq := fmt . Sprintf ( "update %s_auth set recoverycode=?, recoverytime=NOW() where username = ?" , c . TablePrefix )
2020-07-18 12:03:31 +00:00
_ , err := c . db . Exec ( qq , recoverycode , username )
2020-06-04 20:02:46 +00:00
if err == nil {
2020-07-23 22:12:44 +00:00
SendRecoveryEmail ( email , username , string ( recoverycode ) )
2018-12-27 21:49:59 +00:00
}
}
}
func RecoverByEmail ( e string ) {
var username , email string
2023-09-19 22:09:33 +00:00
q := fmt . Sprintf ( "select username from %s_auth where email ILIKE ?" , c . TablePrefix )
2020-07-18 11:55:19 +00:00
err := c . db . Get ( & username , q , e )
2020-06-04 20:02:46 +00:00
if err != sql . ErrNoRows {
recoverycode := randBytes ( 16 )
2023-09-19 22:09:33 +00:00
qq := fmt . Sprintf ( "update %s_auth set recoverycode=?, recoverytime=NOW() where username = ?" , c . TablePrefix )
2020-06-04 20:02:46 +00:00
_ , err := c . db . Exec ( qq , recoverycode , username )
if err == nil {
2020-07-23 22:12:44 +00:00
SendRecoveryEmail ( email , username , string ( recoverycode ) )
2018-12-27 21:49:59 +00:00
}
}
}
2018-12-25 19:22:13 +00:00
func randBytes ( n int ) [ ] byte {
2020-06-04 20:02:46 +00:00
randomBytes := make ( [ ] byte , 32 )
_ , err := rand . Read ( randomBytes )
if err != nil {
panic ( err )
}
return [ ] byte ( base32 . StdEncoding . EncodeToString ( randomBytes ) [ : n ] )
2018-12-25 19:22:13 +00:00
}
2020-07-23 22:12:44 +00:00
func SendRegistrationEmail ( recipient , username , password string ) bool {
2018-12-25 19:22:13 +00:00
data := struct {
SiteName string
FromEmail string
UserName string
Pass string
} {
SiteName : c . SiteName ,
FromEmail : c . FromEmail ,
UserName : username ,
Pass : password ,
}
var body bytes . Buffer
err := c . Templates . Registration . Execute ( & body , data )
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.sendRegistrationEmail: Registration template failed to execute: %v returned %s\n" , data , err . Error ( ) )
2018-12-25 19:22:13 +00:00
return false
}
subject := fmt . Sprintf ( "Welcome to %s" , c . SiteName )
2019-01-02 19:04:40 +00:00
err = SendMail ( c . SMTPServer , c . FromEmail , subject , body . String ( ) , recipient )
2018-12-25 19:22:13 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.SendRegistrationEmail: Error sending mail to %s: %s\n" , recipient , err . Error ( ) )
2018-12-25 19:22:13 +00:00
return false
}
return true
}
2020-07-23 22:12:44 +00:00
func SendAlertEmail ( username , recipient , message string ) bool {
2018-12-27 21:49:59 +00:00
data := struct {
SiteName string
FromEmail string
UserName string
2020-06-04 20:02:46 +00:00
Activity string
2018-12-27 21:49:59 +00:00
} {
SiteName : c . SiteName ,
FromEmail : c . FromEmail ,
UserName : username ,
Activity : message ,
}
var body bytes . Buffer
2020-07-23 22:18:55 +00:00
err := c . Templates . Alert . Execute ( & body , data )
2018-12-27 21:49:59 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.sendAlertEmail: Alert template failed to execute: %v returned %s\n" , data , err . Error ( ) )
2018-12-27 21:49:59 +00:00
return false
}
2020-06-04 20:02:46 +00:00
2020-07-18 11:55:19 +00:00
subject := fmt . Sprintf ( "new Activity Notification on %s" , c . SiteName )
2020-06-04 20:02:46 +00:00
err = SendMail ( c . SMTPServer , c . FromEmail , subject , body . String ( ) , recipient )
2018-12-27 21:49:59 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.sendAlertEmail: Error sending mail to %s: %s\n" , recipient , err . Error ( ) )
2018-12-27 21:49:59 +00:00
return false
}
return true
}
2020-07-23 22:12:44 +00:00
func SendRecoveryEmail ( recipient , username , code string ) bool {
2018-12-27 21:49:59 +00:00
data := struct {
2020-06-04 20:02:46 +00:00
SiteName string
FromEmail string
UserName string
RecoveryCode string
2018-12-27 21:49:59 +00:00
} {
2020-06-04 20:02:46 +00:00
SiteName : c . SiteName ,
FromEmail : c . FromEmail ,
UserName : username ,
RecoveryCode : code ,
2018-12-27 21:49:59 +00:00
}
var body bytes . Buffer
err := c . Templates . Registration . Execute ( & body , data )
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.sendRecoveryEmail: Recovery template failed to execute: %v returned %s\n" , data , err . Error ( ) )
2018-12-27 21:49:59 +00:00
return false
}
2019-01-02 15:21:05 +00:00
subject := fmt . Sprintf ( "Account recovery at %s" , c . SiteName )
2019-01-02 19:04:40 +00:00
err = SendMail ( c . SMTPServer , c . FromEmail , subject , body . String ( ) , recipient )
2018-12-27 21:49:59 +00:00
if err != nil {
2019-01-02 15:21:05 +00:00
log . Printf ( "scsusers.sendRecoveryEmail: Error sending mail to %s: %s\n" , recipient , err . Error ( ) )
2018-12-27 21:49:59 +00:00
return false
}
return true
}
2018-12-25 19:22:13 +00:00
func SetRegistrationTemplate ( t string ) bool {
if len ( t ) != 0 {
r , err := template . New ( "reg" ) . Parse ( t )
if err != nil {
c . Templates . Registration = r
return true
}
}
df := ` <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html></head><body><p>Hello {{ .UserName }} ! Welcome to {{ .SiteName }} ! We've created your account with the username you selected and the following password: {{ .Pass }} <br>You can change your password to whatever you want once you log in.</p></body></html> `
r , err := template . New ( "reg" ) . Parse ( df )
if err != nil {
2019-01-02 15:21:05 +00:00
log . Fatal ( "scsusers.SetRegistrationTemplate: Default registration template MUST compile. Error: " + err . Error ( ) )
2018-12-25 19:22:13 +00:00
}
c . Templates . Registration = r
return false
}
func SetAlertTemplate ( t string ) bool {
if len ( t ) != 0 {
r , err := template . New ( "alert" ) . Parse ( t )
if err != nil {
c . Templates . Alert = r
return true
}
}
2018-12-27 21:49:59 +00:00
df := ` <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html></head><body><p> Hey {{ .UserName }} ! Just letting you know that {{ .Activity }} .<br> You can disable future notifications in your user settings.</p></body></html> `
2018-12-25 19:22:13 +00:00
r , err := template . New ( "alert" ) . Parse ( df )
if err != nil {
2019-01-02 15:21:05 +00:00
log . Fatal ( "scsusers.SetAlertTemplate: Default alert template MUST compile. Error: " + err . Error ( ) )
2018-12-25 19:22:13 +00:00
}
c . Templates . Alert = r
return false
}
func SetRecoveryTemplate ( t string ) bool {
if len ( t ) != 0 {
r , err := template . New ( "recovery" ) . Parse ( t )
if err != nil {
c . Templates . Recovery = r
return true
}
}
2020-07-18 12:03:31 +00:00
df := ` <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html></head><body><p>Hello {{ .UserName }} ! Someone (hopefully you) has attempted an account recovery agt {{ .SiteName }} . If this was yousername, enter the following code to regain access: {{ .RecoveryCode }} <br> If this was not yousername, you can ignore this email.</p></body></html> `
2018-12-25 19:22:13 +00:00
r , err := template . New ( "recovery" ) . Parse ( df )
if err != nil {
2019-01-02 15:21:05 +00:00
log . Fatal ( "scsusers.SetRecoveryTemplate: Default recovery template MUST compile. Error: " + err . Error ( ) )
2018-12-25 19:22:13 +00:00
}
c . Templates . Recovery = r
return false
}
func SendMail ( addr , from , subject , body string , to string ) error {
r := strings . NewReplacer ( "\r\n" , "" , "\r" , "" , "\n" , "" , "%0a" , "" , "%0d" , "" )
c , err := smtp . Dial ( addr )
if err != nil {
return err
}
defer c . Close ( )
if err = c . Mail ( r . Replace ( from ) ) ; err != nil {
return err
}
to = r . Replace ( to )
if err = c . Rcpt ( to ) ; err != nil {
return err
}
w , err := c . Data ( )
if err != nil {
return err
}
2020-08-22 00:16:17 +00:00
date := time . Now ( )
2018-12-25 19:22:13 +00:00
msg := "To: " + to + "\r\n" +
"From: " + from + "\r\n" +
"Subject: " + subject + "\r\n" +
"Content-Type: text/html; charset=\"UTF-8\"\r\n" +
2020-08-22 00:16:17 +00:00
"Date: " + date . Format ( time . RFC1123Z ) + "\r\n" +
2018-12-25 19:22:13 +00:00
"\r\n" + body
_ , err = w . Write ( [ ] byte ( msg ) )
if err != nil {
return err
}
err = w . Close ( )
if err != nil {
return err
}
return c . Quit ( )
}