Skip to content

Commit

Permalink
add new ENV variables + fingerprint generation
Browse files Browse the repository at this point in the history
  • Loading branch information
cedricve committed Jun 27, 2024
1 parent c629fcc commit dc1b72c
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 55 deletions.
16 changes: 7 additions & 9 deletions api/.env
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
EMAIL = "[email protected]"
PASSWORD = "password"
MAIL_PROVIDER=mailgun
EMAIL_FROM=support@uug.ai
EMAIL_FROM_DISPLAYNAME=uug.ai
EMAIL_FROM=support@xxx.io
EMAIL_FROM_DISPLAYNAME=xxx.ai
WELCOME_TEMPLATE=welcome
WELCOME_TITLE=Welcome to Facial Access Control
INVITE_TEMPLATE=invite
INVITE_TITLE="[You're invited] Please complete your profile"
FORGOT_TEMPLATE=forgot
FORGOT_TITLE=Password reset Facial Access Control. You forgot your password
SMTP_SERVER=smtp.domain.com
SMTP_SERVER=smtp.xxxx.org
SMTP_PORT='465'
SMTP_USERNAME=mail@domain.com
SMTP_PASSWORD=
MAILGUN_DOMAIN=mg.domain.com
MAILGUN_API_KEY=
SMTP_USERNAME=mail@mg.xxx.io
SMTP_PASSWORD=xxxx
PRIVATE_KEY="xxxx"
BASE_URL=http://localhost:3000
78 changes: 64 additions & 14 deletions api/controllers/users.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package controllers

import (
"bytes"
"encoding/gob"
"fmt"
"os"
"strconv"
"time"

"github.com/gin-gonic/gin"
"github.com/uug-ai/facial-access-control/api/database"
"github.com/uug-ai/facial-access-control/api/encryption"
"github.com/uug-ai/facial-access-control/api/models"
"github.com/uug-ai/facial-access-control/api/notifications"
"github.com/uug-ai/facial-access-control/api/utils"
)

// user godoc
Expand Down Expand Up @@ -186,25 +192,69 @@ func InviteUser(c *gin.Context) error {
return err
}

mail := notifications.SMTP{
Server: os.Getenv("SMTP_SERVER"),
Port: os.Getenv("SMTP_PORT"),
Username: os.Getenv("SMTP_USERNAME"),
Password: os.Getenv("SMTP_PASSWORD"),
EmailFrom: os.Getenv("EMAIL_FROM"),
EmailTo: user.Email,
TemplateId: "invite",
// Create fingerprint
now := time.Now()
fingerprint := models.UserFingerprint{
Email: user.Email,
FirstName: user.FirstName,
LastName: user.LastName,
Id: user.Id,
Expiration: now.Add(time.Hour * 24 * 7).Unix(), // 1 week (7 days)
Creation: now.Unix(),
}

message := notifications.Message{
Title: "Invitation",
Body: "You have been invited to join the Facial Acces Control",
User: user.Email,
// Serialize fingerprint
var buffer bytes.Buffer
enc := gob.NewEncoder(&buffer)
err := enc.Encode(fingerprint)
if err != nil {
fmt.Println("Error while encoding fingerprint")
return err
}

if err := mail.Send(message); err != nil {
// Encrypt the fingerprint using the ENV variable PRIVATE_KEY
encryptionKey := os.Getenv("PRIVATE_KEY")
if encryptionKey != "" {
encryptedFingerprint, _ := encryption.AesEncrypt(buffer.Bytes(), encryptionKey)

base64Fingerprint := utils.Base64Encode(string(encryptedFingerprint))
fprint := utils.EncodeURL(base64Fingerprint)

mail := notifications.SMTP{
Server: os.Getenv("SMTP_SERVER"),
Port: os.Getenv("SMTP_PORT"),
Username: os.Getenv("SMTP_USERNAME"),
Password: os.Getenv("SMTP_PASSWORD"),
EmailFrom: os.Getenv("EMAIL_FROM"),
EmailTo: user.Email,
TemplateId: "invite",
}

// Get base url
baseUrl := os.Getenv("BASE_URL")
// If baseurl is set, remove the trailing slash
if baseUrl != "" {
baseUrl = utils.RemoveTrailingSlash(baseUrl)
}

message := notifications.Message{
Title: "Invitation",
Body: "You have been invited to join the Facial Acces Control",
User: user.Email,
Data: map[string]string{
"link": baseUrl + "/onboarding/" + fprint,
},
}

if err := mail.Send(message); err != nil {
c.JSON(500, gin.H{
"error": "Failed to send invite to user",
})
return err
}
} else {
c.JSON(500, gin.H{
"error": "Failed to send invite to user",
"error": "No encryption key found",
})
return err
}
Expand Down
24 changes: 16 additions & 8 deletions api/models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,32 @@ package models

type User struct {
Id int `json:"id" bson:"id"`
FirstName string `json:"firstname" bson:"firstname"`
FirstName string `json:"firstname" bson:"firstname"`
LastName string `json:"lastname" bson:"lastname"`
Email string `json:"email" bson:"email"`
Password string `json:"password" bson:"password"`
Role string `json:"role" bson:"role"`
Language string `json:"language" bson:"language"`

}

type Authentication struct {
Email string `json:"email" bson:"email"`
Email string `json:"email" bson:"email"`
Password string `json:"password" bson:"password"`
}

type Authorization struct {
Code int `json:"code" bson:"code"`
Token string `json:"token" bson:"token"`
Expire string `json:"expire" bson:"expire"`
Email string `json:"email" bson:"email"`
Role string `json:"role" bson:"role"`
Code int `json:"code" bson:"code"`
Token string `json:"token" bson:"token"`
Expire string `json:"expire" bson:"expire"`
Email string `json:"email" bson:"email"`
Role string `json:"role" bson:"role"`
}

type UserFingerprint struct {
Id int `json:"id" bson:"id"`
Email string `json:"email" bson:"email"`
FirstName string `json:"firstname" bson:"firstname"`
LastName string `json:"lastname" bson:"lastname"`
Expiration int64 `json:"expiration" bson:"expiration"`
Creation int64 `json:"creation" bson:"creation"`
}
1 change: 1 addition & 0 deletions api/notifications/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ type Message struct {
Email string `json:"email,omitempty" bson:"email,omitempty"`
DataUsage string `json:"data_usage,omitempty" bson:"data_usage,omitempty"`
Data map[string]string `json:"data,omitempty" bson:"data,omitempty"`
Fingerprint string `json:"fingerprint,omitempty" bson:"fingerprint,omitempty"`
}
22 changes: 1 addition & 21 deletions api/notifications/smtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,7 @@ func (smtp SMTP) Send(message Message) error {
// This function will replace the variables in the email template. We have following variables available:
// - {{user}}: user that triggered the message
// - {{text}}: text of the message
// - {{link}}: link to the media (recording)
//
// - {{thumbnail}}: image (either a base64 or a url).
// - {{classifications}}: list of classifications detected in the recording.
//
// - {{timezone}}: timezone of the account generating the event
//
// - {{date}}: date of the media
// - {{time}}: time of the media
// - {{datetime}}: datetime of the media
//
// - {{eventdate}}: date of the notification
// - {{eventtime}}: time of the notification
// - {{eventdatetime}}: datetime of the notification
//
// - {{devicename}}: device generating the event
// - {{deviceid}}: device generating the event
// - {{sites}}: the list of sites the device is part of
// - {{groups}}: the list of groups the device is part of
// - {{numberOfMedia}}: number of media attached to the message
// - {{dataUsage}}: data usage of the message
// - {{link}}: link to the invite page

func ReplaceValues(body string, message Message) string {

Expand Down
154 changes: 151 additions & 3 deletions api/utils/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package utils

import (
"encoding/base64"
"fmt"
"math/rand"
"strconv"
"time"

"golang.org/x/crypto/bcrypt"
)
Expand All @@ -20,10 +24,154 @@ func PrintASCIIArt() {
}

func Hash(str string) (string, error) {
hashed, err := bcrypt.GenerateFromPassword([]byte(str), bcrypt.DefaultCost)
return string(hashed), err
hashed, err := bcrypt.GenerateFromPassword([]byte(str), bcrypt.DefaultCost)
return string(hashed), err
}

func IsSame(str string, hashed string) bool {
return bcrypt.CompareHashAndPassword([]byte(hashed), []byte(str)) == nil
return bcrypt.CompareHashAndPassword([]byte(hashed), []byte(str)) == nil
}

func init() {
rand.Seed(time.Now().UnixNano())
}

const letterBytes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

func RandStringBytesRmndr(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
}
return string(b)
}

func Contains(arr []string, str string) bool {
for _, a := range arr {
if a == str {
return true
}
}
return false
}

func GetDate(timezone string, timestamp int64) string {
t := time.Unix(timestamp, 0)
loc, _ := time.LoadLocation(timezone)
return t.In(loc).Format("02-01-2006")
}

func GetHour(timezone string, timestamp int64) int {
t := time.Unix(timestamp, 0)
loc, _ := time.LoadLocation(timezone)
return t.In(loc).Hour()
}

func GetTime(timezone string, timestamp int64) string {
t := time.Unix(timestamp, 0)
loc, _ := time.LoadLocation(timezone)
return t.In(loc).Format("15:04:05")
}

func StringToInt(s string) int {
i, err := strconv.Atoi(s)
if err != nil {
return 0
}
return i
}

func GetDateTime(timezone string, timestamp int64) string {
t := time.Unix(timestamp, 0)
loc, _ := time.LoadLocation(timezone)
return t.In(loc).Format("02-01-2006 - 15:04:05")
}

func GetDateTimeLong(timezone string, timestamp int64) string {
t := time.Unix(timestamp, 0)
loc, _ := time.LoadLocation(timezone)
timeInLocation := t.In(loc)

suffix := "th"
switch timeInLocation.Day() {
case 1, 21, 31:
suffix = "st"
case 2, 22:
suffix = "nd"
case 3, 23:
suffix = "rd"
}

return timeInLocation.Format("January 2" + suffix + " 2006, 15:04:05")
}

func GetDateShort(timezone string, timestamp int64) string {
t := time.Unix(timestamp, 0)
loc, _ := time.LoadLocation(timezone)
timeInLocation := t.In(loc)

suffix := "th"
switch timeInLocation.Day() {
case 1, 21, 31:
suffix = "st"
case 2, 22:
suffix = "nd"
case 3, 23:
suffix = "rd"
}

return timeInLocation.Format("January 2" + suffix + ",Monday")
}

func GetTimestamp(timezone string, date string) int64 {
layout := "02-01-2006"
loc, _ := time.LoadLocation(timezone)
t, err := time.ParseInLocation(layout, date, loc)
if err != nil {
fmt.Println(err)
return -1
}
return t.Unix()
}

func Uniq(slice []string) []string {
// create a map with all the values as key
uniqMap := make(map[string]struct{})
for _, v := range slice {
uniqMap[v] = struct{}{}
}

// turn the map keys into a slice
uniqSlice := make([]string, 0, len(uniqMap))
for v := range uniqMap {
uniqSlice = append(uniqSlice, v)
}
return uniqSlice
}

func Base64Encode(value string) string {
data := []byte(value)
str := base64.StdEncoding.EncodeToString(data)
return str
}

func Base64Decode(value string) (string, error) {
data, _ := base64.StdEncoding.DecodeString(value)
return string(data), nil
}

func EncodeURL(value string) string {
return base64.RawURLEncoding.EncodeToString([]byte(value))
}

func DecodeURL(value string) (string, error) {
data, _ := base64.RawURLEncoding.DecodeString(value)
return string(data), nil
}

func RemoveTrailingSlash(value string) string {
if value[len(value)-1:] == "/" {
return value[:len(value)-1]
}
return value
}

0 comments on commit dc1b72c

Please sign in to comment.