Skip to content
This repository has been archived by the owner on Mar 10, 2020. It is now read-only.

Commit

Permalink
pade.chat is a PWA
Browse files Browse the repository at this point in the history
  • Loading branch information
deleolajide committed May 23, 2019
1 parent 2ded540 commit 8e52be0
Show file tree
Hide file tree
Showing 13 changed files with 442 additions and 50 deletions.
8 changes: 7 additions & 1 deletion changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,15 @@ <h1>
Chat API Plugin Changelog
</h1>

<p><b>0.9.5 Release 1</b> -- March 15, 2019</p>
<p><b>0.9.5 Release 2</b> -- Appril 25, 2019</p>

This comment has been minimized.

Copy link
@wrooot

wrooot May 23, 2019

April

<ul>
<li>Added support for inband-registration</li>
</ul>

<p><b>0.9.5 Release 1</b> -- March 14, 2019</p>
<ul>
<li>Support Kerberos for Windows SSO</li>
<li>Added pade.chat</li>
</ul>

<p><b>0.9.4 Release 9</b> -- February 28, 2019</p>
Expand Down
4 changes: 2 additions & 2 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
<name>Chat API</name>
<description>RESTful API with Server Sent Events (SSE) for Openfire Meetings</description>
<author>Ignite Realtime</author>
<version>0.9.5 Release 1</version>
<date>03/15/2019</date>
<version>0.9.5 Release 3</version>
<date>05/31/2019</date>
<minServerVersion>4.1.5</minServerVersion>
<minJavaVersion>1.8</minJavaVersion>
<adminconsole>
Expand Down
Binary file added src/apps/images/check-solid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/apps/images/image_192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/apps/images/image_512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/apps/images/times-solid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions src/apps/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!doctype html>
<html lang="en">
<head>
<title>Converse</title>
<link rel="shortcut icon" href="icon.png" type="image/gif" />

<!-- General /-->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

<!-- PWA /-->
<meta name="theme-color" content="#ffffff">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="manifest" href="manifest.json">

<!-- iOS /-->
<meta name="apple-mobile-web-app-title" content="create-pwa">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<link rel="apple-touch-icon" href="images/touch-icon.png">

<!-- iOS splash screens -->
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)" href="images/apple-launch-1125x2436.png">
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" href="images/apple-launch-750x1334.png">
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3)" href="images/apple-launch-1242x2208.png">
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" href="images/apple-launch-640x1136.png">
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)" href="images/apple-launch-1536x2048.png">
<link rel="apple-touch-startup-image" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)" href="images/apple-launch-1668x2224.png">
<link rel="apple-touch-startup-image" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)" href="images/apple-launch-2048x2732.png">

<!-- Common decency /-->
<meta charset="utf-8">
<link rel="shortcut icon" href="favicon.ico">

<!-- SEO /-->
<meta name="description" content="pade is a unified communications web client.">
<meta name="keywords" content="pade unified communications messaging audio video meetings phone">

<script src="inverse/chrome.js"></script>
<script src="js/jquery.min.js"></script>
<script src="js/libs.bundle.js"></script>
<script src="js/strophe.vcard.js"></script>
<script src="js/moment.js"></script>
<script src="js/sip.js"></script>
<script src="js/etherlynk.js"></script>
<script src="js/background.js"></script>
<script src="index.js"></script>

</head>
<body>
<iframe id="inverse" style="position:fixed; top:0px; left:0px; bottom:0px; right:0px; width:100%; height:100%; border:none; margin:0; padding:0; overflow:hidden;"></iframe>
</body>
</html>
202 changes: 202 additions & 0 deletions src/apps/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
window.addEventListener("load", function()
{
Notification.requestPermission().then(function(result)
{
console.log("Notification.requestPermission", result);
});

document.getElementById("inverse").src="inverse/index.html" + location.hash
});

function getCredentials(callback)
{
if (navigator.credentials)
{
navigator.credentials.get({password: true, federated: {providers: [ 'https://accounts.google.com' ]}, mediation: "silent"}).then(function(credential)
{
console.log("credential management api get", credential);
if (callback) callback(credential);

}).catch(function(err){
console.error ("credential management api get error", err);
if (callback) callback();
});
}
else {
if (callback) callback();
}
}

function setCredentials(creds)
{
if (navigator.credentials)
{
navigator.credentials.create({password: creds}).then(function(credential)
{
navigator.credentials.store(credential).then(function()
{
console.log("credential management api put", credential);

}).catch(function (err) {
console.error("credential management api put error", err);
});

}).catch(function (err) {
console.error("credential management api put error", err);
});
}
}

var webpush = (function(push)
{
var hostname, username, password, publicKey;

function vapidGetPublicKey(host, user, pass)
{
var getUrl = "https://" + host + "/rest/api/restapi/v1/meet/webpush/" + user;
var options = {method: "GET", headers: {"Authorization": "Basic " + btoa(user + ":" + pass), "Accept":"application/json", "Content-Type":"application/json"}};

console.debug("vapidGetPublicKey", getUrl, options);

fetch(getUrl, options).then(function(response) {return response.json()}).then(function(vapid)
{
if (vapid.publicKey)
{
console.debug("vapidGetPublicKey found", vapid);

publicKey = vapid.publicKey;
hostname = host;
username = user;
password = pass;

navigator.serviceWorker.register('./serviceworker.js', {scope: './'}).then(initialiseState, initialiseError);
} else {
console.error("no web push, vapid public key not available");
}

}).catch(function (err) {
console.error('vapidGetPublicKey error!', err);
});
}

function initialiseError(error)
{
console.error("initialiseError", error);
}

function initialiseState(registration)
{
if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
console.warn('Notifications aren\'t supported.');
return;
}

if (Notification.permission === 'denied') {
console.warn('The user has blocked notifications.');
return;
}

if (!('PushManager' in window)) {
console.warn('Push messaging isn\'t supported.');
return;
}

console.debug("initialiseState", registration);

navigator.serviceWorker.ready.then(function (serviceWorkerRegistration)
{
console.debug("initialiseState ready", serviceWorkerRegistration);

serviceWorkerRegistration.pushManager.getSubscription().then(function (subscription)
{
console.debug("serviceWorkerRegistration getSubscription", subscription);

if (!subscription && publicKey) {
subscribe();
return;
}

// Keep your server in sync with the latest subscriptionId
sendSubscriptionToServer(subscription);
})
.catch(function(err) {
console.warn('Error during getSubscription()', err);
});
});
}

function subscribe()
{
console.debug("subscribe", publicKey);

navigator.serviceWorker.ready.then(function (serviceWorkerRegistration)
{
serviceWorkerRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: base64UrlToUint8Array(publicKey)
})
.then(function (subscription) {
return sendSubscriptionToServer(subscription);
})
.catch(function (e) {
if (Notification.permission === 'denied') {
console.warn('Permission for Notifications was denied');
} else {
console.error('Unable to subscribe to push.', e);
}
});
});
}

function base64UrlToUint8Array(base64UrlData)
{
const padding = '='.repeat((4 - base64UrlData.length % 4) % 4);
const base64 = (base64UrlData + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');

const rawData = atob(base64);
const buffer = new Uint8Array(rawData.length);

for (let i = 0; i < rawData.length; ++i) {
buffer[i] = rawData.charCodeAt(i);
}

return buffer;
}

function sendSubscriptionToServer(subscription)
{
console.debug("sendSubscriptionToServer", subscription);

var key = subscription.getKey ? subscription.getKey('p256dh') : '';
var auth = subscription.getKey ? subscription.getKey('auth') : '';

var subscriptionString = JSON.stringify(subscription); // TODO

console.debug("web push subscription", {
endpoint: subscription.endpoint,
key: key ? btoa(String.fromCharCode.apply(null, new Uint8Array(key))) : '',
auth: auth ? btoa(String.fromCharCode.apply(null, new Uint8Array(auth))) : ''
}, subscription);

var resource = chrome.i18n.getMessage('manifest_shortExtensionName').toLowerCase() + "-" + BrowserDetect.browser + BrowserDetect.version + BrowserDetect.OS;
var putUrl = "https://" + hostname + "/rest/api/restapi/v1/meet/webpush/" + username + "/" + resource;
var options = {method: "PUT", body: JSON.stringify(subscription), headers: {"Authorization": "Basic " + btoa(username + ":" + password), "Accept":"application/json", "Content-Type":"application/json"}};

return fetch(putUrl, options).then(function(response) {
console.debug("subscribe response", response);

}).catch(function (err) {
console.error('subscribe error!', err);
});
}

push.registerServiceWorker = function(host, username, password)
{
vapidGetPublicKey(host, username, password);
}

return push;

}(webpush || {}));
21 changes: 21 additions & 0 deletions src/apps/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"short_name": "pade.chat",
"name": "pade.chat",
"icons": [
{
"src": "images/image_192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "images/image_512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "https://pade.chat/apps",
"background_color": "#FFFFFF",
"theme_color": "#FFFFFF",
"display": "standalone",
"orientation": "portrait"
}
68 changes: 68 additions & 0 deletions src/apps/serviceworker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// install trigger for sw - cache index.html

self.addEventListener('install', function(event) {
var indexPage = new Request('index.html');
event.waitUntil(
fetch(indexPage).then(function(response) {
return caches.open('offline').then(function(cache) {
return cache.put(indexPage, response);
});
}));
});

// activate trigger

self.addEventListener('activate', function (event) {
console.log('Activated', event);
});


// fetch trigger - serve from cache or fetch from server, cache the file if not previously cached
// fix Request method 'PUT' is unsupported error in line 26
self.addEventListener('fetch', function(event) {
event.respondWith(
fetch(event.request).then(function(response) {
return caches.open('offline').then(function(cache) {
try {
cache.put(event.request, response.clone());
} catch (e) {};
return response;
});
}).catch(function (error) {
caches.match(event.request).then(function(resp) {
return resp;
});
})
);
});

// push trigger

self.addEventListener('push', function (event) {
var data = event.data.text();

console.log('Push message', data);
data = JSON.parse(data);

var options = {
body: data.message,
icon: 'icon.png',
vibrate: [100, 50, 100],
data: data,
actions: [
{action: 'read', title: 'Read', icon: 'images/check-solid.png'},
{action: 'ignore', title: 'Ignore', icon: 'images/times-solid.png'},
]
};
event.waitUntil(
self.registration.showNotification(data.title, options)
);
});

self.addEventListener('notificationclick', function(event) {
event.notification.close();

if (event.action === 'read') {
event.waitUntil(clients.openWindow(event.notification.data.url, event.notification.data.url));
}
}, false);
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,11 @@ public void run() {
Log.info("SMTP Listener started");

try {
smtpServer = SMTPServer.port(Integer.valueOf(JiveGlobals.getProperty("ofmeet.email.listener.smtp.port", "25000")))
final InetAddress bindingAddress = InetAddress.getByName(JiveGlobals.getProperty("xmpp.socket.plain.interface", XMPPServer.getInstance().getServerInfo().getHostname()));

smtpServer = SMTPServer
.port(Integer.valueOf(JiveGlobals.getProperty("ofmeet.email.listener.smtp.port", "25000")))
.bindAddress(bindingAddress)
.messageHandlerFactory(new SimpleMessageListenerAdapter(new SimpleMessageListenerImpl()))
.build();

Expand Down
Loading

0 comments on commit 8e52be0

Please sign in to comment.