Prechádzať zdrojové kódy

Added wip smtp notification agent

tobychui 3 rokov pred
rodič
commit
2b1c356dd9
7 zmenil súbory, kde vykonal 566 pridanie a 342 odobranie
  1. 36 28
      go.mod
  2. 289 273
      go.sum
  3. 99 0
      mod/notification/agents/smtpn/smtpn.go
  4. 51 39
      mod/notification/notification.go
  5. 42 0
      notification.go
  6. 3 2
      startup.go
  7. 46 0
      system/www/smtpn.html

+ 36 - 28
go.mod

@@ -3,44 +3,52 @@ module imuslab.com/arozos
 go 1.13
 
 require (
-	github.com/andybalholm/brotli v1.0.0 // indirect
+	cloud.google.com/go/compute v1.6.1 // indirect
+	github.com/Microsoft/go-winio v0.5.2 // indirect
+	github.com/ProtonMail/go-crypto v0.0.0-20220512085406-902f79d34c9f // indirect
+	github.com/andybalholm/brotli v1.0.4 // indirect
 	github.com/boltdb/bolt v1.3.1
-	github.com/dhowden/tag v0.0.0-20200828214007-46e57f75dbfc
+	github.com/dhowden/tag v0.0.0-20201120070457-d52dcb253c63
 	github.com/disintegration/imaging v1.6.2
-	github.com/fclairamb/ftpserverlib v0.8.0
+	github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac
+	github.com/emersion/go-smtp v0.15.0
+	github.com/emirpasic/gods v1.18.1 // indirect
+	github.com/fclairamb/ftpserverlib v0.18.0
 	github.com/fogleman/fauxgl v0.0.0-20200818143847-27cddc103802
 	github.com/fogleman/simplify v0.0.0-20170216171241-d32f302d5046 // indirect
-	github.com/frankban/quicktest v1.10.0 // indirect
-	github.com/gabriel-vasile/mimetype v1.1.0
-	github.com/go-git/go-git/v5 v5.2.0
+	github.com/gabriel-vasile/mimetype v1.4.0
+	github.com/go-git/go-git/v5 v5.4.2
 	github.com/go-ldap/ldap v3.0.3+incompatible
-	github.com/gopherjs/gopherjs v0.0.0-20220221023154-0b2280d3ff96 // indirect
-	github.com/gorilla/sessions v1.2.0
-	github.com/gorilla/websocket v1.4.2
+	github.com/golang/snappy v0.0.4 // indirect
+	github.com/gopherjs/gopherjs v1.17.2 // indirect
+	github.com/gorilla/sessions v1.2.1
+	github.com/gorilla/websocket v1.5.0
 	github.com/grandcat/zeroconf v1.0.0
-	github.com/klauspost/compress v1.10.6 // indirect
-	github.com/klauspost/pgzip v1.2.4 // indirect
-	github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d
-	github.com/mholt/archiver/v3 v3.3.0
-	github.com/miekg/dns v1.1.29 // indirect
+	github.com/kevinburke/ssh_config v1.2.0 // indirect
+	github.com/klauspost/compress v1.15.4 // indirect
+	github.com/koron/go-ssdp v0.0.3
+	github.com/mholt/archiver/v3 v3.5.1
+	github.com/miekg/dns v1.1.49 // indirect
 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
-	github.com/nwaples/rardecode v1.1.0 // indirect
+	github.com/nwaples/rardecode v1.1.3 // indirect
 	github.com/oliamb/cutter v0.2.2
 	github.com/oov/psd v0.0.0-20220121172623-5db5eafcecbb
-	github.com/pierrec/lz4 v2.5.2+incompatible // indirect
-	github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff
+	github.com/pierrec/lz4/v4 v4.1.14 // indirect
+	github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
 	github.com/satori/go.uuid v1.2.0
-	github.com/spf13/afero v1.6.0
-	github.com/tidwall/pretty v1.0.2
+	github.com/sergi/go-diff v1.2.0 // indirect
+	github.com/spf13/afero v1.8.2
+	github.com/tidwall/pretty v1.2.0
 	github.com/ulikunitz/xz v0.5.10 // indirect
-	github.com/valyala/fasttemplate v1.1.0
-	gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 // indirect
-	gitlab.com/NebulousLabs/go-upnp v0.0.0-20181011194642-3a71999ed0d3
-	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
-	golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
-	golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1
-	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
-	golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect
+	github.com/valyala/fasttemplate v1.2.1
+	github.com/xanzy/ssh-agent v0.3.1 // indirect
+	gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6
+	golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 // indirect
+	golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect
+	golang.org/x/net v0.0.0-20220513224357-95641704303c // indirect
+	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
+	golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
+	golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
+	golang.org/x/tools v0.1.10 // indirect
 	gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
-	gopkg.in/sourcemap.v1 v1.0.5 // indirect
 )

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 289 - 273
go.sum


+ 99 - 0
mod/notification/agents/smtpn/smtpn.go

@@ -0,0 +1,99 @@
+package smtpn
+
+/*
+
+	SMTP Notifaiction Agent
+
+	This is the mail sending agent for sending notification to user
+
+*/
+
+import (
+	"io/ioutil"
+	"log"
+	"net/smtp"
+	"strconv"
+	"time"
+
+	"github.com/valyala/fasttemplate"
+	notification "imuslab.com/arozos/mod/notification"
+)
+
+type Agent struct {
+	Hostname              string
+	SMTPSenderDisplayName string
+	SMTPSender            string
+	SMTPPassword          string
+	SMTPDomain            string
+	SMTPPort              int
+	UsernameToEmailMap    map[string]string
+}
+
+func (a Agent) Name() string {
+	return "smtpn"
+}
+
+func (a Agent) Desc() string {
+	return "Notify user throught email"
+}
+
+func (a Agent) IsConsumer() bool {
+	return true
+}
+
+func (a Agent) IsProducer() bool {
+	return false
+}
+
+func (a Agent) ConsumerNotification(incomingNotification *notification.NotificationPayload) error {
+	//Get a notification and send it out
+
+	//Analysis the notification, get the target user's email
+	userEmails := [][]string{}
+
+	for _, username := range incomingNotification.Receiver {
+		userEmail, ok := a.UsernameToEmailMap[username]
+		if ok {
+			userEmails = append(userEmails, []string{username, userEmail})
+		} else {
+			log.Println("[SMTP Notification] Unable to notify " + username + ": Email not set")
+		}
+	}
+
+	//For each user, send out the email
+	for _, thisEntry := range userEmails {
+		thisUser := thisEntry[0]
+		thisEmail := thisEntry[1]
+
+		//Load email template
+		template, _ := ioutil.ReadFile("system/www/smtpn.html")
+		t := fasttemplate.New(string(template), "{{", "}}")
+		s := t.ExecuteString(map[string]interface{}{
+			"receiver":  "Hello " + thisUser + ",",
+			"message":   incomingNotification.Message,
+			"sender":    incomingNotification.Sender,
+			"hostname":  a.Hostname,
+			"timestamp": time.Now().Format("2006-01-02 3:4:5 PM"),
+		})
+
+		msg := []byte("To: " + thisEmail + "\n" +
+			"From: " + a.SMTPSenderDisplayName + " <" + a.SMTPSender + ">\n" +
+			"Subject: " + incomingNotification.Title + "\n" +
+			"MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n" +
+			s + "\n\n")
+
+		//Login to the SMTP server
+		auth := smtp.PlainAuth("", a.SMTPSender, a.SMTPPassword, a.SMTPDomain)
+		err := smtp.SendMail(a.SMTPDomain+":"+strconv.Itoa(a.SMTPPort), auth, a.SMTPSender, []string{thisEmail}, msg)
+		if err != nil {
+			log.Println("[SMTPN] Email sent failed: ", err.Error())
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (a Agent) ProduceNotification(producerListeningEndpoint *notification.AgentProducerFunction) {
+	return
+}

+ 51 - 39
mod/notification/notification.go

@@ -1,6 +1,9 @@
-package main
+package notification
 
-import "container/list"
+import (
+	"container/list"
+	"log"
+)
 
 /*
 	Notification Producer and Consumer Queue
@@ -10,38 +13,28 @@ import "container/list"
 */
 
 type NotificationPayload struct {
-	ID        string   //Notification ID, generate by producer
-	Title     string   //Title of the notification
-	Message   string   //Message of the notification
-	Receiver  []string //Receiver, username in arozos system
-	Sender    string   //Sender, the sender or module of the notification
-	ActionURL string   //URL for futher action or open related pages (as url), leave empty if not appliable
-	IsUrgent  bool     //Label this notification as urgent
+	ID            string   //Notification ID, generate by producer
+	Title         string   //Title of the notification
+	Message       string   //Message of the notification
+	Receiver      []string //Receiver, username in arozos system
+	Sender        string   //Sender, the sender or module of the notification
+	ReciverAgents []string //Agent name that have access to this notification
 }
 
-//Notification Consumer, object that use to consume notification from queue
-type Consumer struct {
-	Name string
-	Desc string
+type AgentProducerFunction func(*NotificationPayload) error
 
-	ListenTopicMode int
-	Notify          func(*NotificationPayload) error
-	ListeningQueue  *NotificationQueue
-}
-
-//Notification Producer, object that use to create and push notification into the queue
-type Producer struct {
-	Name string
-	Desc string
-
-	PushTopicType int
-	TargetQueue   *NotificationQueue
+type Agent interface {
+	//Defination of the agent
+	Name() string                                    //The name of the notification agent, must be unique
+	Desc() string                                    //Basic description of the agent
+	IsConsumer() bool                                //Can receive notification can arozos core
+	IsProducer() bool                                //Can produce notification to arozos core
+	ConsumerNotification(*NotificationPayload) error //Endpoint for arozos -> this agent
+	ProduceNotification(*AgentProducerFunction)      //Endpoint for this agent -> arozos
 }
 
 type NotificationQueue struct {
-	Producers []*Producer
-	Consumers []*Consumer
-
+	Agents      []*Agent
 	MasterQueue *list.List
 }
 
@@ -49,23 +42,42 @@ func NewNotificationQueue() *NotificationQueue {
 	thisQueue := list.New()
 
 	return &NotificationQueue{
-		Producers:   []*Producer{},
-		Consumers:   []*Consumer{},
+		Agents:      []*Agent{},
 		MasterQueue: thisQueue,
 	}
 }
 
-//Add a notification producer into the master queue
-func (n *NotificationQueue) AddNotificationProducer(p *Producer) {
-	n.Producers = append(n.Producers, p)
+//Add a notification agent to the queue
+func (q *NotificationQueue) RegisterNotificationAgent(agent Agent) {
+	q.Agents = append(q.Agents, &agent)
 }
 
-//Add a notification consumer into the master queue
-func (n *NotificationQueue) AddNotificationConsumer(c *Consumer) {
-	n.Consumers = append(n.Consumers, c)
-}
+func (q *NotificationQueue) BroadcastNotification(message *NotificationPayload) error {
+	//Send notification to consumer agents
+	for _, agent := range q.Agents {
+		thisAgent := *agent
+		inAgentList := false
+		for _, enabledAgent := range message.ReciverAgents {
+			if enabledAgent == thisAgent.Name() {
+				//This agent is activated
+				inAgentList = true
+				break
+			}
+		}
+
+		if !inAgentList {
+			//Skip this agent and continue
+			continue
+		}
+
+		//Send this notification via this agent
+		err := thisAgent.ConsumerNotification(message)
+		if err != nil {
+			log.Println("[Notification] Unable to send message via notification agent: " + thisAgent.Name())
+		}
 
-//Push a notifiation to all consumers with same topic type
-func (n *NotificationQueue) PushNotification(TopicType int, message *NotificationPayload) {
+	}
 
+	log.Println("[Notification] Message titled: " + message.Title + " (ID: " + message.ID + ") broadcasted")
+	return nil
 }

+ 42 - 0
notification.go

@@ -0,0 +1,42 @@
+package main
+
+import (
+	"strconv"
+	"time"
+
+	notification "imuslab.com/arozos/mod/notification"
+	"imuslab.com/arozos/mod/notification/agents/smtpn"
+)
+
+var notificationQueue *notification.NotificationQueue
+
+func notificationInit() {
+	//Create a new notification agent
+	notificationQueue = notification.NewNotificationQueue()
+
+	//Register the notification agents
+
+	//SMTP Mail Sender
+	smtpAgent := smtpn.Agent{
+		Hostname:           *host_name,
+		SMTPSender:         "[email protected]",
+		SMTPPassword:       "",
+		SMTPDomain:         "mail.gandi.net",
+		SMTPPort:           587,
+		UsernameToEmailMap: map[string]string{},
+	}
+
+	notificationQueue.RegisterNotificationAgent(smtpAgent)
+
+	go func() {
+		time.Sleep(10 * time.Second)
+		notificationQueue.BroadcastNotification(&notification.NotificationPayload{
+			ID:            strconv.Itoa(int(time.Now().Unix())),
+			Title:         "Disk SMART Error",
+			Message:       "This is a testing notification for showcasing a sample email when DISK SMART error was scanned and discovered.<br> Please visit <a href='https://blog.teacat.io'>here</a> for more information.",
+			Receiver:      []string{"TC", "jk", "ay"},
+			Sender:        "SMART Nightly Scanner",
+			ReciverAgents: []string{"smtpn"},
+		})
+	}()
+}

+ 3 - 2
startup.go

@@ -109,8 +109,9 @@ func RunStartup() {
 	mediaServer_init()
 	security_init()
 	backup_init()
-	OAuthInit() //Oauth system init
-	ldapInit()  //LDAP system init
+	OAuthInit()        //Oauth system init
+	ldapInit()         //LDAP system init
+	notificationInit() //Notification system init
 
 	//Start High Level Services that requires full arozos architectures
 	FTPServerInit() //Start FTP Server Endpoints

+ 46 - 0
system/www/smtpn.html

@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1">
+    <meta name="x-apple-disable-message-reformatting">
+    <title></title>
+    <!--[if mso]>
+    <noscript>
+        <xml>
+            <o:OfficeDocumentSettings>
+                <o:PixelsPerInch>96</o:PixelsPerInch>
+            </o:OfficeDocumentSettings>
+        </xml>
+    </noscript>
+    <![endif]-->
+    <style>
+        table, td, div, h1, p {font-family: Arial, sans-serif;}
+		.theme{
+			background: rgb(0,130,255);
+			background: linear-gradient(90deg, rgba(0,130,255,1) 0%, rgba(62,146,248,1) 46%, rgba(249,249,249,1) 100%);
+		}
+    </style>
+</head>
+<body style="margin:0;padding:0;">
+    <table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#ffffff;">
+        <tr>
+            <td class="theme" style="padding: 1em; color: #595959; color: white;">
+				System Notification from {{hostname}}
+            </td>
+        </tr>
+		<tr>
+            <td style="padding:1.2em;">
+                <p>{{receiver}}</p>
+				<p style="margin-left: 2em;">{{message}}</p>
+				<p>{{sender}}</p>
+            </td>
+        </tr>
+		<tr style="border-top: 1px solid #d4d4d4 !important;">
+            <td style="padding:0.4em; font-size: 0.8em;">
+				This message was sent automatically from {{hostname}} on {{timestamp}}.
+            </td>
+        </tr>
+    </table>
+</body>
+</html>

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov