diff --git a/.gitignore b/.gitignore
index 485acd7..5898eb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,9 @@ static/img/davecat.jpg
static/yoyo-medium.gif
static/leo.goldfish.fyi.png
+
+private_key.txt
+
+public_key.txt
+
+vapid_private.pem
diff --git a/smsproj.py b/smsproj.py
index c9d97de..f5542b3 100644
--- a/smsproj.py
+++ b/smsproj.py
@@ -6,9 +6,12 @@ import time
import pprint
import configparser
import json
-# import re
+import os
import flask
+# import re
+from flask import request, Response, render_template, jsonify, Flask, session
+from pywebpush import webpush, WebPushException
import appdb
import appsms
@@ -20,8 +23,18 @@ config = configparser.ConfigParser()
config.read('config.ini')
app_debug = config.get("app", "debug")
-app = flask.Flask(__name__)
+app = Flask(__name__)
app.secret_key = config.get("auth", "FN_FLASK_SECRET_KEY")
+app.config['SECRET_KEY'] = config.get("auth", "FN_FLASK_SECRET_KEY")
+DER_BASE64_ENCODED_PRIVATE_KEY_FILE_PATH = os.path.join(os.getcwd(),"private_key.txt")
+DER_BASE64_ENCODED_PUBLIC_KEY_FILE_PATH = os.path.join(os.getcwd(),"public_key.txt")
+
+VAPID_PRIVATE_KEY = open(DER_BASE64_ENCODED_PRIVATE_KEY_FILE_PATH, "r+").readline().strip("\n")
+VAPID_PUBLIC_KEY = open(DER_BASE64_ENCODED_PUBLIC_KEY_FILE_PATH, "r+").read().strip("\n")
+
+VAPID_CLAIMS = {
+"sub": "mailto:support@athnex.com"
+}
app.register_blueprint(callback_sms.app)
app.register_blueprint(app_settings.app)
@@ -34,6 +47,13 @@ if app_debug == '1':
else:
app.debug = False
+def send_web_push(subscription_information, message_body):
+ return webpush(
+ subscription_info=subscription_information,
+ data=message_body,
+ vapid_private_key=VAPID_PRIVATE_KEY,
+ vapid_claims=VAPID_CLAIMS
+ )
@app.route('/')
def index():
@@ -105,7 +125,7 @@ def getNumMessages(number):
'''Return the messages from a single DID in json form'''
# This gets the mssages based on the provided from or two DID
if not app_auth.is_logged_in():
- return json.dumps({'error': 'Unable to send SMS, you are not logged in'})
+ return json.dumps({'error': 'You are not logged in.'})
# We need to take and compare the authIDforDID, gotta add use id
# to getNumSMSLog and pull the id from result.
@@ -174,6 +194,20 @@ def markallunread():
return json.dumps({'status': 'success'})
return False
+@app.route("/subscription/", methods=["GET", "POST"])
+def subscription():
+ """
+ POST creates a subscription
+ GET returns vapid public key which clients uses to send around push notification
+ """
+
+ if request.method == "GET":
+ return Response(response=json.dumps({"public_key": VAPID_PUBLIC_KEY}),
+ headers={"Access-Control-Allow-Origin": "*"}, content_type="application/json")
+
+ subscription_token = request.get_json("subscription_token")
+ return Response(status=201, mimetype="application/json")
+
@app.route('/submitMessage', methods=['POST'])
def submitMessage():
@@ -215,6 +249,24 @@ def submitMessage():
"targetdid": targetDid})
return returndata
+@app.route("/push_v1/",methods=['POST'])
+def push_v1():
+ message = "Push Test v1"
+ print("is_json",request.is_json)
+
+ if not request.json or not request.json.get('sub_token'):
+ return jsonify({'failed':1})
+
+ print("request.json",request.json)
+
+ token = request.json.get('sub_token')
+ try:
+ token = json.loads(token)
+ send_web_push(token, message)
+ return jsonify({'success':1})
+ except Exception as e:
+ print("error",e)
+ return jsonify({'failed':str(e)})
@app.route('/testAjax')
def testAjax():
diff --git a/static/main.js b/static/main.js
new file mode 100644
index 0000000..3248200
--- /dev/null
+++ b/static/main.js
@@ -0,0 +1,171 @@
+// main.js
+
+'use strict';
+
+// const applicationServerPublicKey = "BNbxGYNMhEIi9zrneh7mqV4oUanjLUK3m+mYZBc62frMKrEoMk88r3Lk596T0ck9xlT+aok0fO1KXBLV4+XqxYM=";
+const pushButton = document.querySelector('.js-push-btn');
+
+let isSubscribed = false;
+let swRegistration = null;
+
+function urlB64ToUint8Array(base64String) {
+ const padding = '='.repeat((4 - base64String.length % 4) % 4);
+ const base64 = (base64String + padding)
+ .replace(/\-/g, '+')
+ .replace(/_/g, '/');
+
+ const rawData = window.atob(base64);
+ const outputArray = new Uint8Array(rawData.length);
+
+ for (let i = 0; i < rawData.length; ++i) {
+ outputArray[i] = rawData.charCodeAt(i);
+ }
+ return outputArray;
+}
+
+function updateBtn() {
+ if (Notification.permission === 'denied') {
+ pushButton.textContent = 'Push Messaging Blocked.';
+ pushButton.disabled = true;
+ updateSubscriptionOnServer(null);
+ return;
+ }
+
+ if (isSubscribed) {
+ pushButton.textContent = 'Disable Push Messaging';
+ } else {
+ pushButton.textContent = 'Enable Push Messaging';
+ }
+
+ pushButton.disabled = false;
+}
+
+function updateSubscriptionOnServer(subscription) {
+ // TODO: Send subscription to application server
+
+ const subscriptionJson = document.querySelector('.js-subscription-json');
+ const subscriptionDetails =
+ document.querySelector('.js-subscription-details');
+
+ if (subscription) {
+ subscriptionJson.textContent = JSON.stringify(subscription);
+ subscriptionDetails.classList.remove('is-invisible');
+ } else {
+ subscriptionDetails.classList.add('is-invisible');
+ }
+}
+
+function subscribeUser() {
+ const applicationServerPublicKey = localStorage.getItem('applicationServerPublicKey');
+ const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
+ swRegistration.pushManager.subscribe({
+ userVisibleOnly: true,
+ applicationServerKey: applicationServerKey
+ })
+ .then(function(subscription) {
+ console.log('User is subscribed.');
+
+ updateSubscriptionOnServer(subscription);
+ localStorage.setItem('sub_token',JSON.stringify(subscription));
+ isSubscribed = true;
+
+ updateBtn();
+ })
+ .catch(function(err) {
+ console.log('Failed to subscribe the user: ', err);
+ updateBtn();
+ });
+}
+
+function unsubscribeUser() {
+ swRegistration.pushManager.getSubscription()
+ .then(function(subscription) {
+ if (subscription) {
+ return subscription.unsubscribe();
+ }
+ })
+ .catch(function(error) {
+ console.log('Error unsubscribing', error);
+ })
+ .then(function() {
+ updateSubscriptionOnServer(null);
+
+ console.log('User is unsubscribed.');
+ isSubscribed = false;
+
+ updateBtn();
+ });
+}
+
+function initializeUI() {
+ pushButton.addEventListener('click', function() {
+ pushButton.disabled = true;
+ if (isSubscribed) {
+ unsubscribeUser();
+ } else {
+ subscribeUser();
+ }
+ });
+
+ // Set the initial subscription value
+ swRegistration.pushManager.getSubscription()
+ .then(function(subscription) {
+ isSubscribed = !(subscription === null);
+
+ updateSubscriptionOnServer(subscription);
+
+ if (isSubscribed) {
+ console.log('User IS subscribed.');
+ } else {
+ console.log('User is NOT subscribed.');
+ }
+
+ updateBtn();
+ });
+}
+
+if ('serviceWorker' in navigator && 'PushManager' in window) {
+ console.log('Service Worker and Push is supported');
+
+ navigator.serviceWorker.register("/static/sw.js")
+ .then(function(swReg) {
+ console.log('Service Worker is registered', swReg);
+
+ swRegistration = swReg;
+ initializeUI();
+ })
+ .catch(function(error) {
+ console.error('Service Worker Error', error);
+ });
+} else {
+ console.warn('Push meapplicationServerPublicKeyssaging is not supported');
+ pushButton.textContent = 'Push Not Supported';
+}
+
+function push_message() {
+ console.log("sub_token", localStorage.getItem('sub_token'));
+ $.ajax({
+ type: "POST",
+ url: "/push_v1/",
+ contentType: 'application/json; charset=utf-8',
+ dataType:'json',
+ data: JSON.stringify({'sub_token':localStorage.getItem('sub_token')}),
+ success: function( data ){
+ console.log("success",data);
+ },
+ error: function( jqXhr, textStatus, errorThrown ){
+ console.log("error",errorThrown);
+ }
+ });
+}
+
+$(document).ready(function(){
+ $.ajax({
+ type:"GET",
+ url:'/subscription/',
+ success:function(response){
+ console.log("response",response);
+ localStorage.setItem('applicationServerPublicKey',response.public_key);
+ }
+ })
+});
diff --git a/static/sw.js b/static/sw.js
new file mode 100644
index 0000000..544bcf2
--- /dev/null
+++ b/static/sw.js
@@ -0,0 +1,64 @@
+// sw.js
+
+'use strict';
+
+/* eslint-disable max-len */
+
+// const applicationServerPublicKey = "BNbxGYNMhEIi9zrneh7mqV4oUanjLUK3m+mYZBc62frMKrEoMk88r3Lk596T0ck9xlT+aok0fO1KXBLV4+XqxYM=";
+
+/* eslint-enable max-len */
+
+function urlB64ToUint8Array(base64String) {
+ const padding = '='.repeat((4 - base64String.length % 4) % 4);
+ const base64 = (base64String + padding)
+ .replace(/\-/g, '+')
+ .replace(/_/g, '/');
+
+ const rawData = window.atob(base64);
+ const outputArray = new Uint8Array(rawData.length);
+
+ for (let i = 0; i < rawData.length; ++i) {
+ outputArray[i] = rawData.charCodeAt(i);
+ }
+ return outputArray;
+}
+
+self.addEventListener('push', function(event) {
+ console.log('[Service Worker] Push Received.');
+ console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
+
+ const title = 'Push Codelab';
+ const options = {
+ body: `"${event.data.text()}"`,
+ icon: 'images/icon.png',
+ badge: 'images/badge.png'
+ };
+
+ event.waitUntil(self.registration.showNotification(title, options));
+});
+
+self.addEventListener('notificationclick', function(event) {
+ console.log('[Service Worker] Notification click Received.');
+
+ event.notification.close();
+
+ event.waitUntil(
+ clients.openWindow('https://developers.google.com/web/')
+ );
+});
+
+self.addEventListener('pushsubscriptionchange', function(event) {
+ console.log('[Service Worker]: \'pushsubscriptionchange\' event fired.');
+ const applicationServerPublicKey = localStorage.getItem('applicationServerPublicKey');
+ const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
+ event.waitUntil(
+ self.registration.pushManager.subscribe({
+ userVisibleOnly: true,
+ applicationServerKey: applicationServerKey
+ })
+ .then(function(newSubscription) {
+ // TODO: Send to application server
+ console.log('[Service Worker] New subscription: ', newSubscription);
+ })
+ );
+});
diff --git a/templates/inbox.html b/templates/inbox.html
index 3487848..da6e10f 100644
--- a/templates/inbox.html
+++ b/templates/inbox.html
@@ -52,6 +52,7 @@ $("document").ready(function() {
alert("FAIL");
});
}
+ getInboxData();
});
diff --git a/templates/include/header.html b/templates/include/header.html
index a6be53d..f943305 100644
--- a/templates/include/header.html
+++ b/templates/include/header.html
@@ -4,6 +4,8 @@
+
+