Skip to content

Commit

Permalink
Send notifications to all server
Browse files Browse the repository at this point in the history
0.0.1+PoC
  • Loading branch information
C0Newb committed Dec 3, 2022
1 parent b3d4e7f commit 3575790
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
Expand Down Expand Up @@ -46,10 +50,9 @@
import kotlin.NotImplementedError;

public class ConnectionManager {
protected boolean hasNegotiated;
protected Date lastCommunicatedTime;
protected java.net.Socket Socket;
// protected AsyncHttpClient AsyncHttpClient; // Eh maybe not
private boolean hasNegotiated;
private Date lastCommunicatedTime;
// protected AsyncHttpClient AsyncHttpClient; // Eh maybe not .. but probably

private IPAddress IPAddress;
private ConfigItem Configuration;
Expand All @@ -76,10 +79,79 @@ public void sendRequest(JSONObject requestData) {

// This sends a POST request
// apiURL is the 'api' or command you're calling, request data the ... data, and callback ... nothing for now
public JSONObject sendRequest(String apiURL, JSONObject requestData) throws JSONException { //, Callable<Void> callback) {
public JSONObject sendRequest(String apiURL, JSONObject requestData) throws JSONException, MalformedURLException { //, Callable<Void> callback) {
String response = "{}";

/*
{
connectionId: "conInitUUID",
command: "/api/v1/server/....",
data: "{}"
}
example:
{
"conInitUUID": "{{conInitUUID}}",
"command":"/api/v1/echo",
"data":"{\"sampleKey\":\"sampleValue\",\"message\":\"Hey!\",\"boolean\":true}"
}
*/

String packet = "{ \"conInitUUID\": \"" + this.conInitUUID + "\", \"command\": \"" + apiURL + "\" }"; // \"data\": \"" + requestData.toString().replaceAll("\"", "\\\\\"") + "\" }";
JSONObject obj = new JSONObject(packet);
obj.put("data", requestData.toString());

response = sendHTTPPostRequest(new URL("http://" + this.IPAddress.toString() + "/api/v1/server/socket/" + this.socketUUID + "/http"), obj.toString());

return new JSONObject(response);
}

return new JSONObject("{}");
public String sendHTTPPostRequest(URL url, String data) {
Log.d("Connection-Manager", "Sending request to: " + url);
try {
HttpURLConnection connectionA = null;
connectionA = (HttpURLConnection)url.openConnection();
connectionA.setRequestMethod("POST");
connectionA.setRequestProperty("Content-Type", "application/json");
connectionA.setRequestProperty("Accept", "application/json");
connectionA.setDoOutput(true);
//connection.setConnectTimeout(10000);
//connection.setReadTimeout(12500);

// Write the data
Log.d("Connection-Manager", "Data to be sent: " + data);
//try(OutputStream stream = connectionA.getOutputStream()) {
// byte[] input = data.getBytes(StandardCharsets.UTF_8);
// stream.write(input, 0, input.length);
//}

OutputStream out = new BufferedOutputStream(connectionA.getOutputStream());
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
writer.write(data);
writer.flush();
writer.close();
out.close();


int responseCode = connectionA.getResponseCode();

StringBuilder response = new StringBuilder();
try(BufferedReader br = new BufferedReader(new InputStreamReader(connectionA.getInputStream(), StandardCharsets.UTF_8))) {
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
}
connectionA.disconnect();

Log.d("Connection-Manager", "Got code: " + responseCode + "\nReceived response: " + response.toString());
this.lastCommunicatedTime = new Date();
return response.toString();
} catch (IOException e) {
Log.d("Connection-Manager", "Server does not exist, or we cannot not connect");
e.printStackTrace();
}
return "{}";
}

public boolean initiateConnection() {
Expand Down Expand Up @@ -207,6 +279,10 @@ public boolean initiateConnection() {
// validate confMsg
this.socketUUID = serverResponse2.getString("socketUUID");

this.hasNegotiated = true;

// at some point

Log.d("Connection-Manager", "SocketUUID: " + this.socketUUID);

// we good
Expand Down Expand Up @@ -261,12 +337,12 @@ public IPAddress getIPAddress() {
return IPAddress;
}

public Socket getSocket() {
return Socket;
}

public Date getLastCommunicatedTime() {
return lastCommunicatedTime;
}

public boolean getHasNegotiated() {
return this.hasNegotiated;
}

}
Original file line number Diff line number Diff line change
@@ -1,18 +1,66 @@
package com.neptune.app.Backend;

import android.app.Notification;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.util.Log;

import java.util.Map;

public class NeptuneNotification extends NotificationListenerService {
public class NeptuneNotification {

private Notification statusBarNotification;
private StatusBarNotification statusBarNotification;
private Map<String, Boolean> pushedServers;

public Notification statusBarNotification(Notification statusBarNotification, Map<String, Boolean> pushedServers) {
public String title = "";
public String text = "";
public String appPackageName = "";
public String subtext = "";
public String appName = "";
public int id = 0;


public NeptuneNotification(StatusBarNotification notification, Context context) throws Exception {
this.statusBarNotification = notification;

Bundle extras = notification.getNotification().extras;

if (extras.getString("android.title") == null) { //Some notifications are not handled correctly, so we'll just skip em
throw new Exception("Invalid notification");
}

String title = extras.getString("android.title");
String text = "";
if (extras.getCharSequence("android.text") != null) {
text = extras.getCharSequence("android.text").toString();
}
int id1 = extras.getInt(Notification.EXTRA_SMALL_ICON);
Bitmap id = notification.getNotification().largeIcon;

this.title = title;
this.appPackageName = notification.getPackageName();
this.text = text;
this.subtext = extras.getString("android.subtext");

PackageManager pm = context.getPackageManager();
ApplicationInfo ai;
try {
ai = pm.getApplicationInfo( this.appPackageName, 0);
} catch (final PackageManager.NameNotFoundException e) {
ai = null;
}
this.appName = (String) (ai != null ? pm.getApplicationLabel(ai) : "(unknown)");

this.id = notification.getId();
}

public NeptuneNotification(StatusBarNotification statusBarNotification, Map<String, Boolean> pushedServers) {
this.statusBarNotification = statusBarNotification;
this.pushedServers = pushedServers;

return null;
}

public void activate() {
Expand All @@ -23,7 +71,8 @@ public void dismiss() {

}

public void pushToServer() {

@Override
public String toString() {
return "{ \"action\": \"create\", \"title\": \"" + this.title + "\", \"contents\": { \"text\": \"" + this.text + "\" }, \"applicationPackage\": \"" + this.appPackageName + "\", \"applicationName\": \"" + this.appName + "\", \"notificationId\": \"" + this.id + "\", \"type\": \"text\" }";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.neptune.app.MainActivity;

import java.io.ByteArrayOutputStream;

public class NotificationListenerService extends android.service.notification.NotificationListenerService {
Expand Down Expand Up @@ -73,6 +75,9 @@ public void onNotificationPosted(StatusBarNotification notification) {
i.putExtra("notification_event", "onNotificationPosted :" + notification.getPackageName() + "\n");
sendBroadcast(i); */

// Note, only do global filtering here. Things like THIS app get filtered..
// The Server class will filter out whatever it doesn't want

//Different Approach to see if this would be better/works (May need help with figuring this out)
String pack = notification.getPackageName();
String ticker = "";
Expand Down Expand Up @@ -113,6 +118,14 @@ public void onNotificationPosted(StatusBarNotification notification) {
message.putExtra("icon", byteArray);
}

NeptuneNotification notify = null;
try {
notify = new NeptuneNotification(notification, getApplicationContext());
MainActivity.serverManager.processNotification(notify);
} catch (Exception e) {
e.printStackTrace();
}

LocalBroadcastManager.getInstance(context).sendBroadcast(message);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import android.app.Notification;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.net.MalformedURLException;
import java.util.Date;

import kotlin.NotImplementedError;
Expand Down Expand Up @@ -44,9 +46,16 @@ public void setupConnectionManager() {
connectionManager.initiateConnection();
}

public boolean sendNotification(Notification notification) {

return false;
public void sendNotification(NeptuneNotification notification) {
try {
if (connectionManager.getHasNegotiated()) {
connectionManager.sendRequest("/api/v1/server/sendNotification", new JSONObject(notification.toString()));
}
} catch (JSONException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}

public boolean sendClipboard(Object object ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

public class ServerManager {

private static Map<String, Server> servers;
private static Map<String, Server> servers = new HashMap<String, Server>();

public ServerManager() {

public ServerManager () {
servers = new HashMap<String, Server>();
}

public void removeServer(Server s) {
Expand All @@ -19,15 +19,9 @@ public void addServer(Server s) {
servers.put(s.getFriendlyName(), s);
}

public ServerManager serverManager() {
this.servers = this.servers; //I think we should set this equal to a new HashMap or something. A type of map that lets the frontend access the info and
//add, delete, or edit the information the easiest.
return null;
}

public Server pair(String name, IPAddress ipAddress) {
public void pair(String name, IPAddress ipAddress) {

return null;
}

public boolean unpair(Server server) {
Expand All @@ -36,12 +30,10 @@ public boolean unpair(Server server) {
}

public Server getServer(String serverId) {

return this.servers.get(serverId);
}

public Server[] getServers() {

return servers.values().toArray(new Server[0]); // Maybe?
}

Expand All @@ -53,4 +45,10 @@ public void saveServers() {

}

public void processNotification(NeptuneNotification notification) {
for (Server server : servers.values()) {
server.sendNotification(notification);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import com.neptune.app.Backend.ServerManager;

public class MainActivity extends AppCompatActivity implements RenameDialog.RenameDialogListener{
public ServerManager serverManager = new ServerManager();
public static ServerManager serverManager = new ServerManager();
public Server server;
//public Config config
private TextView devName;
Expand Down
6 changes: 3 additions & 3 deletions Documents/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
"Packet" set between `Server<->client`
```json
{
"connectionId": "{currentConnectionId}",
"conInitUUID": "{currentConnectionId}",
"command": "{command being called (URL)}",
"data": "{data being sent}",
}
```
This data is a layer on the _actual_ data the client is sending. The `data` portion is encrypted using the shared AES key and contains the command, clientId, and command parameters.
The server or client would receive this "packet" of data and peel it (decrypt the `data` portion) to read the request/response of the other application. This is to provide always applied encryption to requests and responses.\
Before we have a connectionId, we add `"negotiating": true` to signify we're setting that up.\
If the server receives a packet without a connectionId, only the `newSocketConnection` command will be accepted.
Before we have a conInitUUID, we add `"negotiating": true` to signify we're setting that up.\
If the server receives a packet without a conInitUUID, only the `newSocketConnection` command will be accepted.


## Key negotiation, pairing
Expand Down
2 changes: 1 addition & 1 deletion Server/src/Classes/Notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class Notification extends EventEmitter {
// send the notification
this.#notifierNotification = Notifier.notify({
title: data.title,
message: data.contents.subtext + "\n" + data.contents.text,
message: data.contents.text, // data.contents.subtext + "\n" +
id: data.notificationId,
}, function(err, response, metadata) { // this is kinda temporary, windows gets funky blah blah blah read note at top
if (err) {
Expand Down
3 changes: 1 addition & 2 deletions Server/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const debug = process.env;
const displaySilly = false; // output the silly log level to console (it goes every other level > silly, silly is the lowest priority, literal spam)
Error.stackTraceLimit = (debug)? 8 : 4;

Neptune.version = new Version(0, 0, 1, ((debug)?"debug":"release"), "notifier");
Neptune.version = new Version(0, 0, 1, ((debug)?"debug":"release"), "PoC");

global.Neptune = Neptune; // Anywhere down the chain you can use process.Neptune. Allows us to get around providing `Neptune` to everything

Expand Down Expand Up @@ -598,7 +598,6 @@ async function main() {

if (req.socket.remoteAddress !== "::1") {
client.IPAddress = new IPAddress(req.socket.remoteAddress, "25560");
console.log(client.IPAddress);
}


Expand Down

0 comments on commit 3575790

Please sign in to comment.