setting server smtp settings is done

This commit is contained in:
George Shaw 2017-12-05 16:53:27 -06:00
parent b4e16a6841
commit ce9a597787
8 changed files with 355 additions and 13 deletions

52
pkg/api/email/get_smtp.go Normal file
View file

@ -0,0 +1,52 @@
package email
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/Ennovar/gPanel/pkg/database"
)
func GetSMTP(res http.ResponseWriter, req *http.Request, logger *log.Logger, dir string) bool {
if req.Method != "GET" {
logger.Println(req.URL.Path + "::" + req.Method + "::" + strconv.Itoa(http.StatusMethodNotAllowed) + "::" + http.StatusText(http.StatusMethodNotAllowed))
http.Error(res, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return false
}
ds, err := database.Open(dir + database.DB_SETTINGS)
if err != nil || ds == nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
defer ds.Close()
var smtpDbData struct {
Type string `json:"type"`
Username string `json:"username"`
// Password string `json:"password"`
Server string `json:"server"`
Port int `json:"port"`
}
err = ds.Get(database.BUCKET_GENERAL, []byte("smtp"), &smtpDbData)
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
b, err := json.Marshal(smtpDbData)
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
res.WriteHeader(http.StatusOK)
res.Write(b)
return true
}

66
pkg/api/email/set_smtp.go Normal file
View file

@ -0,0 +1,66 @@
package email
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/Ennovar/gPanel/pkg/database"
"github.com/Ennovar/gPanel/pkg/emailer"
)
func SetSMTP(res http.ResponseWriter, req *http.Request, logger *log.Logger, dir string) bool {
if req.Method != "POST" && req.Method != "UPDATE" {
logger.Println(req.URL.Path + "::" + req.Method + "::" + strconv.Itoa(http.StatusMethodNotAllowed) + "::" + http.StatusText(http.StatusMethodNotAllowed))
http.Error(res, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return false
}
var smtpRequestData struct {
Type string `json:"type"`
Username string `json:"username"`
Password string `json:"password"`
Server string `json:"server"`
Port int `json:"port"`
}
err := json.NewDecoder(req.Body).Decode(&smtpRequestData)
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusBadRequest)
return false
}
// Test Authentication
_, err = emailer.New(smtpRequestData.Type, emailer.Credentials{
Username: smtpRequestData.Username,
Password: smtpRequestData.Password,
Server: smtpRequestData.Server,
Port: smtpRequestData.Port,
})
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusBadRequest)
return false
}
ds, err := database.Open(dir + database.DB_SETTINGS)
if err != nil || ds == nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
defer ds.Close()
err = ds.Put(database.BUCKET_GENERAL, []byte("smtp"), smtpRequestData)
if err != nil {
logger.Println(req.URL.Path + "::" + err.Error())
http.Error(res, err.Error(), http.StatusInternalServerError)
return false
}
res.WriteHeader(http.StatusNoContent)
return true
}

View file

@ -4,6 +4,7 @@ package database
import (
"encoding/json"
"errors"
"strings"
"time"
"github.com/boltdb/bolt"
@ -11,14 +12,19 @@ import (
// Database constants
const (
DB_MAIN = "datastore.db"
DB_MAIN = "datastore.db"
DB_SETTINGS = "settings.db"
)
// Bucket constants
const (
// DB_MAIN BUCKETS
BUCKET_USERS = "users"
BUCKET_PORTS = "ports"
BUCKET_FILTERED_IPS = "filtered_ips"
// DB_SETTINGS BUCKETS
BUCKET_GENERAL = "general"
)
// Error codes
@ -45,19 +51,28 @@ func Open(filepath string) (*Datastore, error) {
// Ensure that all top-level buckets exist
err = ds.handle.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(BUCKET_USERS))
if err != nil {
return err
if strings.HasSuffix(filepath, DB_MAIN) {
_, err := tx.CreateBucketIfNotExists([]byte(BUCKET_USERS))
if err != nil {
return err
}
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_PORTS))
if err != nil {
return err
}
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_FILTERED_IPS))
if err != nil {
return err
}
}
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_PORTS))
if err != nil {
return err
}
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_FILTERED_IPS))
if err != nil {
return err
if strings.HasSuffix(filepath, DB_SETTINGS) {
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_GENERAL))
if err != nil {
return err
}
}
return nil

74
pkg/emailer/emailer.go Normal file
View file

@ -0,0 +1,74 @@
package emailer
import (
"errors"
"net/smtp"
"strconv"
)
type Credentials struct {
Username string
Password string
Server string
Port int
}
type Emailer struct {
auth smtp.Auth
cred Credentials
}
func New(eType string, creds Credentials) (*Emailer, error) {
var a smtp.Auth
switch eType {
case "crammd5":
a = smtp.CRAMMD5Auth(creds.Username, creds.Password)
default:
a = smtp.PlainAuth("", creds.Username, creds.Password, creds.Server)
}
if a == nil {
return nil, errors.New("unable to authenticate")
}
return &Emailer{
auth: a,
cred: creds,
}, nil
}
// SendSimple function will fill out the to/subject email headers for you and allow
// you to just input a string as the email body.
func (e *Emailer) SendSimple(to string, subject string, body string) error {
if e.auth == nil {
return errors.New("smtp server authentication has expired")
}
m := []byte("To:" + to + "\r\n" +
"Subject:" + subject + "\r\n" +
"\r\n" +
body + "\r\n")
err := smtp.SendMail(e.cred.Server+":"+strconv.Itoa(e.cred.Port), e.auth, e.cred.Username, []string{to}, m)
if err != nil {
return err
}
return nil
}
// SendCustom function will not fill out the to/subject email headers for you and allow
// you to send a completely custom message in the form of bytes.
func (e *Emailer) SendCustom(to string, msg []byte) error {
if e.auth == nil {
return errors.New("smtp server authentication has expired")
}
err := smtp.SendMail(e.cred.Server+":"+strconv.Itoa(e.cred.Port), e.auth, e.cred.Username, []string{to}, msg)
if err != nil {
return err
}
return nil
}

View file

@ -9,6 +9,7 @@ import (
"strings"
"github.com/Ennovar/gPanel/pkg/api/bundle"
"github.com/Ennovar/gPanel/pkg/api/email"
logapi "github.com/Ennovar/gPanel/pkg/api/log"
"github.com/Ennovar/gPanel/pkg/api/server"
"github.com/Ennovar/gPanel/pkg/api/user"
@ -86,6 +87,10 @@ func (con *Controller) apiHandler(res http.ResponseWriter, req *http.Request) (b
return true, logapi.Read(res, req, con.APILogger, con.Directory)
case "/log/delete":
return true, logapi.Truncate(res, req, con.APILogger, con.Directory)
case "/email/set_smtp":
return true, email.SetSMTP(res, req, con.APILogger, con.Directory)
case "/email/get_smtp":
return true, email.GetSMTP(res, req, con.APILogger, con.Directory)
default:
return false, false
}

View file

@ -0,0 +1,68 @@
var smtpModal = jQuery('.smtp-settings-modal');
jQuery('._js_smtp-credentials').on('click', function(e){
e.preventDefault();
var xhr = new XMLHttpRequest();
xhr.open('GET', 'api/email/get_smtp', true);
xhr.send();
xhr.onloadend = function() {
if(xhr.status == 200) {
var resp = JSON.parse(xhr.response);
if(resp["type"] == "crammd5") {
jQuery('#smtpType').val(resp["type"]).change();
}
jQuery('#smtpUsername').val(resp["username"]);
jQuery('#smtpServer').val(resp["server"]);
jQuery('#smtpPort').val(resp["port"]);
}
smtpModal.modal('show');
}
});
jQuery('._js_smtp-settings-form').on('submit', function(e){
e.preventDefault();
var flag = false;
jQuery(this).find('input').each(function(i){
if(jQuery(this) && jQuery(this).val()) return true;
else {
flag = true;
return false;
}
});
if(flag) {
alert('All inputs need to be filled out.');
return;
}
var requestData = {};
requestData["type"] = jQuery(this).find('#smtpType').val();
requestData["username"] = jQuery(this).find('#smtpUsername').val();
requestData["password"] = jQuery(this).find('#smtpPassword').val();
requestData["server"] = jQuery(this).find('#smtpServer').val();
requestData["port"] = parseInt(jQuery(this).find('#smtpPort').val());
var xhr = new XMLHttpRequest();
xhr.open(jQuery(this).attr('method'), jQuery(this).attr('action'), true);
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
xhr.send(JSON.stringify(requestData));
xhr.onloadend = function() {
if(xhr.status == 204) {
alert("New SMTP Settings Connect Successfully and are Saved.");
}
else {
if(xhr.response != undefined && xhr.response.length != 0) {
alert('Error: ' + xhr.response);
}
else {
alert('An error has occurred, refresh and try again. If problem persists please contact your administrator.');
}
}
}
});

View file

@ -278,6 +278,53 @@
</div>
</div>
<!-- SMTP Settings Modal -->
<div class="modal fade smtp-settings-modal" tabindex="-1" role="dialog" aria-labelledby="smtp-settings-modal" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">SMTP Settings</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="_js_smtp-settings-form" action="api/email/set_smtp" method="POST">
<div class="form-group">
<label for="smtpType">Authentication Type</label>
<select class="form-control" id="smtpType">
<option selected value="plain">Plain</option>
<option value="crammd5">CRAM-MD5</option>
</select>
</div>
<div class="form-group">
<label for="smtpUsername">Username</label>
<input type="text" class="form-control" id="smtpUsername" placeholder="Username" value="">
</div>
<div class="form-group">
<label for="smtpPassword">Password</label>
<input type="password" class="form-control" id="smtpPassword" placeholder="Password" value="">
</div>
<div class="form-group">
<label for="smtpServer">Server</label>
<input type="text" class="form-control" id="smtpServer" placeholder="Server" value="">
</div>
<div class="form-group">
<label for="smtpPort">Port</label>
<input type="number" class="form-control" id="smtpPort" aria-describedby="newBundleAccountPortHelp" min="0" max="65535" value="587">
</div>
<div class="btn-group" role="group">
<button type="submit" class="btn btn-primary">Test & Set SMTP Settings</button>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-12">
@ -321,6 +368,20 @@
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">Server Settings</h4>
<h6 class="card-subtitle mb-4 text-muted">Set or update various settings, such as smtp credentials, that the server uses</h6>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-primary _js_smtp-credentials">SMTP Credentials</button>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="sticky-footer">
@ -366,6 +427,8 @@
<script type="text/javascript" src="assets/js/panelHandlers/users/new.js"></script>
<script type="text/javascript" src="assets/js/panelHandlers/users/delete.js"></script>
<script type="text/javascript" src="assets/js/panelHandlers/users/new_password.js"></script>
<script type="text/javascript" src="assets/js/panelHandlers/settings/smtp.js"></script>
<!-- KEEP AT BOTTOM OF BODY TAGS -->
</body>
</html>

View file

@ -73,7 +73,6 @@
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
<script type="text/javascript" src="assets/js/formHandlers/login.js"></script>
<script type="text/javascript" src="assets/js/formHandlers/register.js"></script>
<script type="text/javascript" src="assets/js/formHandlers/search.js"></script>
<!-- KEEP AT BOTTOM OF BODY TAGS -->
</body>