Skip to content

Commit

Permalink
Browser notifications (#284)
Browse files Browse the repository at this point in the history
* added WebNotifications request icon

* web notifications

* web notifications

* web notifications, add https support

* web notifications, add https support

* web notifications, add https support

* web notifications, add https support

* web notifications, add https support

documentation update

* web notifications, add https support

documentation update

Co-authored-by: Dan Farrelly <djfarrelly@users.noreply.github.com>
  • Loading branch information
frankdekker and djfarrelly committed Mar 28, 2020
1 parent 8607d26 commit db8dfd7
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 10 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ For convenient use with Grunt, try [grunt-maildev](https://github.com/xavierprio
--web-ip <ip address> IP Address to bind HTTP service to, defaults to --ip
--web-user <user> HTTP user for GUI
--web-pass <password> HTTP password for GUI
--https Switch from http to https protocol
--https-key <file> The file path to the ssl private key
--https-cert <file> The file path to the ssl cert file
--base-pathname <path> base path for URLs
--disable-web Disable the use of the web interface. Useful for unit testing
--hide-extensions <extensions> Comma separated list of SMTP extensions to NOT advertise
Expand Down
12 changes: 10 additions & 2 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,16 @@
<i class="fa fa-envelope a"></i>
MailDev
</a>
<div class="autoshow-toggle">
<i class="fa" ng-class="{'fa-bell' : autoShow, 'fa-bell-o': !autoShow}" ng-click="toggleAutoShow()" title="Automatically show new emails as they arrive"></i>
<div class="options-toggle">
<i class="option fa"
ng-if="notificationsSupported"
ng-class="{'fa-comment disabled' : webNotifications, 'fa-comment-o': !webNotifications}"
ng-click="enableNotifications()"
title="Show browser notification when emails arrive"></i>
<i class="option fa"
ng-class="{'fa-bell' : autoShow, 'fa-bell-o': !autoShow}"
ng-click="toggleAutoShow()"
title="Automatically show new emails as they arrive"></i>
</div>
</div>
<div>
Expand Down
38 changes: 37 additions & 1 deletion app/scripts/controllers/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
/**
* Main App Controller -- Manage all emails visible in the list
*/
var refreshTimeout = null
var notificationTimeout = null

app.controller('MainCtrl', [
'$scope', '$rootScope', '$http', 'Email', '$route', '$location', 'Favicon',
function ($scope, $rootScope, $http, Email, $route, $location, Favicon) {
$scope.items = []
$scope.configOpen = false
$scope.currentItemId = null
$scope.notificationsSupported = 'Notification' in window
$scope.webNotifications = window.Notification && window.Notification.permission === 'granted'
$scope.autoShow = false
$scope.unreadItems = 0

Expand Down Expand Up @@ -38,7 +42,6 @@ app.controller('MainCtrl', [
}
})

var refreshTimeout = null
$rootScope.$on('newMail', function (e, newEmail) {
// update model
$scope.items.push(newEmail)
Expand All @@ -54,6 +57,18 @@ app.controller('MainCtrl', [
$scope.$apply()
}, 200)
}

// show notifications
if (!notificationTimeout && $scope.webNotifications) {
notificationTimeout = setTimeout(function () {
notificationTimeout = null
}, 2000)
new window.Notification('MailDev', { body: newEmail.subject, icon: 'favicon.ico' })
.addEventListener('click', function () {
$location.path('/email/' + newEmail.id)
$scope.$apply()
})
}
})

$rootScope.$on('deleteMail', function (e, email) {
Expand Down Expand Up @@ -93,6 +108,27 @@ app.controller('MainCtrl', [
$scope.autoShow = !$scope.autoShow
}

$scope.enableNotifications = function () {
if (window.Notification && window.Notification.permission === 'granted') {
window.alert('To disable notifications, revoke the permissions in your browser.')
return
}
window.Notification.requestPermission().then(function (permissions) {
$scope.webNotifications = permissions === 'granted'
}).catch(function () {
window.alert('Unable to enable web notifications. See console for more information')
})
if (!window.isSecureContext && window.console) {
console.info(
'Web notifications can only be enabled on websites with https.\n\n' +
'You can enable https for MailDev with self-signed certificate. See `docs/https.md`\n\n' +
'For Firefox you can circumvent this restriction temporarily:\n' +
'In the address bar type `about:config`, and toggle `dom.webnotifications.allowinsecure` \n' +
'Don\'t forget to reset it again after enabling notifications in MailDev'
)
}
}

// Initialize the view
loadData()

Expand Down
2 changes: 1 addition & 1 deletion app/styles/style.css

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions assets/styles/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -384,9 +384,19 @@ code {
background: $brandLighter;
}

.autoshow-toggle {
.options-toggle {
float: right;
cursor: pointer;
color: white;
padding-top: 3px;

> .option {
color: white;
cursor: pointer;
+ .option {
margin-left: 5px;
}

&.disabled {
cursor: default;
}
}
}
32 changes: 32 additions & 0 deletions docs/https.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# HTTPS
By default MailDev will run on the http protocol. For Web Notification support you'll need
to run MailDev on https. This can be done with a self signed certificate.

## Create certificate
Generate the certificate:
```shell script
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/maildev.key -out /etc/ssl/certs/maildev.crt
```

Answer the FQDN question with your domain name or ip:
```shell script
Common Name (e.g. server FQDN or YOUR name) []: 192.168.1.103
```

Files created:
- /etc/ssl/private/maildev.key
- /etc/ssl/certs/maildev.crt

## Start MailDev with https
Add the following arguments to your MailDev startup:
```shell script
--https
--https-key /etc/ssl/private/maildev.key
--https-cert /etc/ssl/certs/maildev.crt
```

## Open maildev with https
```
https:\\192.168.1.103:1080
```
As it's a self signed certificate, you need to accept it in your browser.
11 changes: 10 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ module.exports = function (config) {
.version(version)
.option('-s, --smtp <port>', 'SMTP port to catch emails [1025]', process.env.MAILDEV_SMTP_PORT || '1025')
.option('-w, --web <port>', 'Port to run the Web GUI [1080]', process.env.MAILDEV_WEB_PORT || '1080')
.option('--https', 'Switch from http to https protocol')
.option('--https-key <file>', 'The file path to the ssl private key')
.option('--https-cert <file>', 'The file path to the ssl cert file')
.option('--ip <ip address>', 'IP Address to bind SMTP service to', process.env.MAILDEV_IP || '0.0.0.0')
.option('--outgoing-host <host>', 'SMTP host for outgoing emails', process.env.MAILDEV_OUTGOING_HOST)
.option('--outgoing-port <port>', 'SMTP port for outgoing emails', process.env.MAILDEV_OUTGOING_PORT)
Expand Down Expand Up @@ -76,9 +79,15 @@ module.exports = function (config) {
}

if (!config.disableWeb) {
const secure = {
https: config.https,
cert: config.httpsCert,
key: config.httpsKey
}

// Default to run on same IP as smtp
const webIp = config.webIp ? config.webIp : config.ip
web.start(config.web, webIp, mailserver, config.webUser, config.webPass, config.basePathname)
web.start(config.web, webIp, mailserver, config.webUser, config.webPass, config.basePathname, secure)

if (config.open) {
const open = require('opn')
Expand Down
22 changes: 20 additions & 2 deletions lib/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
const express = require('express')
const cors = require('cors')
const http = require('http')
const https = require('https')
const fs = require('fs')
const socketio = require('socket.io')
const routes = require('./routes')
const auth = require('./auth')
Expand Down Expand Up @@ -73,9 +75,25 @@ web.server = null
* Start the web server
*/

web.start = function (port, host, mailserver, user, password, basePathname) {
web.start = function (port, host, mailserver, user, password, basePathname, secure) {
const app = express()
web.server = http.createServer(app)
if (secure.https) {
if (fs.existsSync(secure.key) === false) {
logger.error('Unable to find https secure key. Please specify key file via -https-key argument')
return
}
if (fs.existsSync(secure.cert) === false) {
logger.error('Unable to find https secure cert. Please specify cert file via -https-cert argument')
return
}
const options = {
key: fs.readFileSync(secure.key),
cert: fs.readFileSync(secure.cert)
}
web.server = https.createServer(options, app)
} else {
web.server = http.createServer(app)
}

if (user && password) {
app.use(auth(user, password))
Expand Down

0 comments on commit db8dfd7

Please sign in to comment.