commit ced1e978575eb74dd0eb4c2a5a3652c888b1456b Author: Dave Umrysh Date: Mon Mar 15 11:29:57 2021 -0600 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e52b80f --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store + +# Generated by package manager +#node_modules/ + +# Generated by Cordova +#/plugins/ +/platforms/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..8072b32 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +sixtyfour (The App) +============== +A messaging bridge between Matrix and 8x8 utilizing Android's Notification intents and a [maubot plugin](https://git.umycode.com/dave/maubot-sixtyfour) + +WARNING: This is a total hack. Consider it a proof of concept rather than a production ready app + +You will need to set up a project for Google Cloud Messaging to make this work ([more information](https://cloud.ibm.com/docs/mobilepush?topic=mobilepush-push_step_1)) + +License +------------ + +Some of the code I borrowed specifies their own copy license. For any other code assume it falls under [WTFPL](http://www.wtfpl.net/txt/copying/) \ No newline at end of file diff --git a/config.xml b/config.xml new file mode 100644 index 0000000..72c408e --- /dev/null +++ b/config.xml @@ -0,0 +1,31 @@ + + + SixtyFour + + 8x8 to Matrix bridge + + + Dave Umrysh + + + + + + + + + + + + + + + + + + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..f423af0 --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "com.umycode.sixtyfour", + "displayName": "SixtyFour", + "version": "1.0.0", + "description": "An app that bridges 8x8 and Matrix", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "ecosystem:cordova" + ], + "author": "Apache Cordova Team", + "license": "Apache-2.0", + "devDependencies": { + "cordova-android": "^9.0.0", + "cordova-plugin-background-mode": "git+https://git.umycode.com/dave/cordova-plugin-run-in-background.git", + "cordova-plugin-device": "^2.0.3", + "cordova-plugin-whitelist": "^1.3.4", + "cordova-support-google-services": "^1.3.2", + "phonegap-plugin-multidex": "^1.0.0", + "phonegap-plugin-push": "^2.3.0", + "cordova-plugin-reply-to-notification": "git+https://git.umycode.com/dave/cordova-plugin-reply-to-notification.git" + }, + "cordova": { + "plugins": { + "cordova-plugin-whitelist": {}, + "cordova-plugin-background-mode": {}, + "phonegap-plugin-push": { + "ANDROID_SUPPORT_V13_VERSION": "27.+", + "FCM_VERSION": "17.0.+" + }, + "cordova-plugin-device": {}, + "cordova-plugin-reply-to-notification": {} + }, + "platforms": [ + "android" + ] + }, + "dependencies": {} +} diff --git a/www/css/index.css b/www/css/index.css new file mode 100644 index 0000000..ecea7e8 --- /dev/null +++ b/www/css/index.css @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +* { + -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */ +} + +body { + -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */ + -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */ + -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */ + background-color:#E4E4E4; + background-image:linear-gradient(to bottom, #A7A7A7 0%, #E4E4E4 51%); + font-family: system-ui, -apple-system, -apple-system-font, 'Segoe UI', 'Roboto', sans-serif; + font-size:12px; + height:100vh; + margin:0px; + padding:0px; + /* Padding to avoid the "unsafe" areas behind notches in the screen */ + padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px); + text-transform:uppercase; + width:100%; +} + +/* Portrait layout (default) */ +.app { + background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */ + position:absolute; /* position in the center of the screen */ + left:50%; + top:50%; + height:50px; /* text area height */ + width:225px; /* text area width */ + text-align:center; + padding:180px 0px 0px 0px; /* image height is 200px (bottom 20px are overlapped with text) */ + margin:-115px 0px 0px -112px; /* offset vertical: half of image height and text area height */ + /* offset horizontal: half of text area width */ +} + +/* Landscape layout (with min-width) */ +@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) { + .app { + background-position:left center; + padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */ + margin:-90px 0px 0px -198px; /* offset vertical: half of image height */ + /* offset horizontal: half of image width and text area width */ + } +} + +h1 { + font-size:24px; + font-weight:normal; + margin:0px; + overflow:visible; + padding:0px; + text-align:center; +} + +.event { + border-radius:4px; + color:#FFFFFF; + font-size:12px; + margin:0px 30px; + padding:2px 0px; +} + +.event.listening { + background-color:#333333; + display:block; +} + +.event.received { + background-color:#4B946A; + display:none; +} + +#deviceready.ready .event.listening { display: none; } +#deviceready.ready .event.received { display: block; } + +@keyframes fade { + from { opacity: 1.0; } + 50% { opacity: 0.4; } + to { opacity: 1.0; } +} + +.blink { + animation:fade 3000ms infinite; + -webkit-animation:fade 3000ms infinite; +} + + +@media screen and (prefers-color-scheme: dark) { + body { + background-image:linear-gradient(to bottom, #585858 0%, #1B1B1B 51%); + } +} diff --git a/www/img/logo.png b/www/img/logo.png new file mode 100644 index 0000000..9519e7d Binary files /dev/null and b/www/img/logo.png differ diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..d8a6a57 --- /dev/null +++ b/www/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + sixyfour + + +
+

SixyFour

+ +
+ + + + diff --git a/www/js/index.js b/www/js/index.js new file mode 100644 index 0000000..4d1f894 --- /dev/null +++ b/www/js/index.js @@ -0,0 +1,176 @@ +var my_8x8_name = "Dave Umrysh"; +var hostUrl = "https://matrix.example.com"; // Location of your Matrix server +var webhook_secret = "UGfmxJyv49Sus2Y32dE7juXYMvp"; // Random key you set in your sixtyfour matrix bot +var instance_name = "sixtyfourinstance"; + +var android_id = ""; +var devicePlatform = ""; + +document.addEventListener('deviceready', onDeviceReady, false); + +function onDeviceReady() { + // Cordova is now initialized. Have fun! + + console.log('Running cordova-' + cordova.platformId + '@' + cordova.version); + document.getElementById('deviceready').classList.add('ready'); + + + android_id = device.uuid; + devicePlatform = device.platform; + + cordova.plugins.backgroundMode.on('activate', function() { + cordova.plugins.backgroundMode.disableWebViewOptimizations(); + }); + cordova.plugins.backgroundMode.enable(); + cordova.plugins.backgroundMode.disableBatteryOptimizations(); + + // Set up the GCM + setUpGCM(); + + startListening(); +} + +function startListening(){ + + replyToNotification.listen(function(n){ + console.log("Received notification " + JSON.stringify(n) ); + + if(n.package == "org.vom8x8.sipua"){ + // Check for rooms + if(n.title == my_8x8_name){ + // This was my message out + // Post to the bot channel + var who_sent_it = n.title.replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"'); + var params = JSON.stringify({ "secret": webhook_secret, "message": "**"+who_sent_it+"**: "+n.text.replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"') }); + postToMatrix(hostUrl+"/_matrix/maubot/plugin/"+instance_name+"/webhook/r0?room=%21aaaaaaaaaaaaaaaaaa:matrix.example.com",params); + }else if(n.title == "John Smith"){ + var who_sent_it = n.title.replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"'); + var params = JSON.stringify({ "secret": webhook_secret, "message": "**"+who_sent_it+"**: "+n.text.replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"') }); + postToMatrix(hostUrl+"/_matrix/maubot/plugin/"+instance_name+"/webhook/r0?room=%21bbbbbbbbbbbbbbbbbb:matrix.example.com",params); + + + // Add other DM rooms here + + + + }else if(n.conversationTitle == "Room #1"){ + var who_sent_it = n.title.replaceAll("Room #1: ","").replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"'); + var params = JSON.stringify({ "secret": webhook_secret, "message": "**"+who_sent_it+"**: "+n.text.replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"') }); + postToMatrix(hostUrl+"/_matrix/maubot/plugin/"+instance_name+"/webhook/r0?room=%21ccccccccccccccccc:matrix.example.com",params); + + + // Add other rooms here + + + }else{ + var who_sent_it = n.title.replaceAll("All Company: ","").replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"'); + var params = JSON.stringify({ "secret": webhook_secret, "message": "**"+who_sent_it+"**: "+n.text.replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"') }); + postToMatrix(hostUrl+"/_matrix/maubot/plugin/"+instance_name+"/webhook/r0?room=%21dddddddddddddddd:matrix.example.com",params); + } + } + + }, function(e){ + console.log("Notification Error " + e); + }); +} + +function postTo8x8(room,message){ + var room_name = ""; + + if(room == "!bbbbbbbbbbbbbbbbbb:matrix.example.com"){ + room_name = "John Smith"; + + // Add other DM rooms here + + + }else if(room == "!ccccccccccccccccc:matrix.example.com"){ + room_name = "Room #1"; + + + // Add other rooms here + + + }else if(room == "!dddddddddddddddd:matrix.example.com"){ + room_name = "All Company"; + } + + if(room_name != ""){ + var temp = { + "room_name":room_name, + "message":message + }; + replyToNotification.replytonotification(temp, function (s) { + // Send errors to the bot channel + console.log(s); + + var params = JSON.stringify({ "secret": webhook_secret, "message": "**8x8 Error**: "+s.replaceAll("\r\n","").replaceAll("\r","").replaceAll("\n","").replaceAll('"','\"') }); + postToMatrix(hostUrl+"/_matrix/maubot/plugin/"+instance_name+"/webhook/r0?room=%21aaaaaaaaaaaaaaaaaa:matrix.example.com",params); + }, function (e) { + console.log(e); + }); + } +} + + +function postToMatrix(url,message){ + var http = new XMLHttpRequest(); + http.open("POST", url, true); + //Send the proper header information along with the request + http.setRequestHeader("Content-type", "application/json"); + + //http.onreadystatechange = function() { + // console.log(http.status+"|"+http.responseText); + //}; + + http.send(message); + console.log("sent message to matrix") +} + + +function setUpGCM(){ + if(typeof device !== 'undefined'){ + pushNotification = PushNotification.init({ + android: {}, + ios: { + alert: "true", + badge: "true", + sound: "true", + clearBadge: "true" + } + }); + + pushNotification.on('registration', function(data) { + window.localStorage.setItem("gcm_key", data.registrationId); + // Try to send it off + sendGCMtoServer(); + }); + + pushNotification.on('notification', function(data) { + // data.message, + // data.title, + // data.count, + // data.sound, + // data.image, + // data.additionalData + postTo8x8(data.title,data.message); + }); + + pushNotification.on('error', function(e) { + console.log("error: "+e.message); + }); + } +} + +function sendGCMtoServer(){ + var gcm_key = window.localStorage.getItem("gcm_key"); + + if(gcm_key == null || gcm_key == ""){ + setUpGCM(); + } + + if(gcm_key != null && gcm_key != ""){ + // Send to server + var params = JSON.stringify({ "secret": webhook_secret, "gcm": gcm_key }); + postToMatrix(hostUrl+"/_matrix/maubot/plugin/"+instance_name+"/webhook/r1?gcm",params); + } +} \ No newline at end of file