const char *kPLVCapability = "palaverapp.com";
const char *kPLVCommand = "PALAVER";
+const char *kPLVPushTokenKey = "PUSH-TOKEN";
const char *kPLVPushEndpointKey = "PUSH-ENDPOINT";
const char *kPLVMentionKeywordKey = "MENTION-KEYWORD";
const char *kPLVMentionChannelKey = "MENTION-CHANNEL";
class PLVHTTPNotificationSocket : public PLVHTTPSocket {
public:
- PLVHTTPNotificationSocket(CModule *pModule, const CString &sToken, const CString &sMethod, const CString &sURL, MCString &mcsHeaders, const CString &sContent) : PLVHTTPSocket(pModule, sMethod, sURL, mcsHeaders, sContent) {
- m_sToken = sToken;
+ PLVHTTPNotificationSocket(CModule *pModule, const CString &sIdentifier, const CString &sMethod, const CString &sURL, MCString &mcsHeaders, const CString &sContent) : PLVHTTPSocket(pModule, sMethod, sURL, mcsHeaders, sContent) {
+ m_sIdentifier = sIdentifier;
}
virtual void HandleStatusCode(unsigned int status);
private:
- CString m_sToken;
+ CString m_sIdentifier;
};
class CDevice {
public:
- CDevice(const CString &sToken) {
- m_sToken = sToken;
+ CDevice(const CString &sIdentifier) {
+ m_sIdentifier = sIdentifier;
m_bInNegotiation = false;
m_uiBadge = 0;
}
m_sVersion = sVersion;
}
- CString GetToken() const {
- return m_sToken;
+ CString GetIdentifier() const {
+ return m_sIdentifier;
+ }
+
+ void SetPushToken(const CString &sToken) {
+ m_sPushToken = sToken;
+ }
+
+ CString GetPushToken() const {
+ return m_sPushToken;
}
void SetPushEndpoint(const CString &sEndpoint) {
void ResetDevice() {
m_bInNegotiation = false;
m_sVersion = "";
+ m_sPushToken = "";
m_sPushEndpoint = "";
m_bShowMessagePreview = true;
SetVersion(sValue);
} else if (sKey.Equals(kPLVPushEndpointKey)) {
SetPushEndpoint(sValue);
+ } else if (sKey.Equals(kPLVPushTokenKey)) {
+ SetPushToken(sValue);
} else if (sKey.Equals(kPLVShowMessagePreviewKey)) {
SetShowMessagePreview(sValue.Equals("true"));
}
}
void Write(CFile& File) const {
- File.Write("BEGIN " + GetToken() + "\n");
+ File.Write("BEGIN " + GetIdentifier() + "\n");
if (GetVersion().empty() == false) {
File.Write("SET VERSION " + GetVersion() + "\n");
File.Write("SET " + CString(kPLVPushEndpointKey) + " " + GetPushEndpoint() + "\n");
}
+ if (GetPushToken().empty() == false) {
+ File.Write("SET " + CString(kPLVPushTokenKey) + " " + GetPushToken() + "\n");
+ }
+
for (VCString::const_iterator it = m_vMentionKeywords.begin();
it != m_vMentionKeywords.end(); ++it) {
const CString& sKeyword = *it;
MCString mcsHeaders;
- mcsHeaders["Authorization"] = CString("Bearer " + GetToken());
+ CString token = GetPushToken();
+ if (token.empty()) {
+ token = GetIdentifier();
+ }
+
+ mcsHeaders["Authorization"] = CString("Bearer " + token);
mcsHeaders["Content-Type"] = "application/json";
CString sJSON = "{";
}
sJSON += "}";
- PLVHTTPSocket *pSocket = new PLVHTTPNotificationSocket(&module, GetToken(), "POST", GetPushEndpoint(), mcsHeaders, sJSON);
+ PLVHTTPSocket *pSocket = new PLVHTTPNotificationSocket(&module, token, "POST", GetPushEndpoint(), mcsHeaders, sJSON);
module.AddSocket(pSocket);
}
if (m_uiBadge != 0) {
MCString mcsHeaders;
- mcsHeaders["Authorization"] = CString("Bearer " + GetToken());
+ CString token = GetPushToken();
+ if (token.empty()) {
+ token = GetIdentifier();
+ }
+ mcsHeaders["Authorization"] = CString("Bearer " + token);
mcsHeaders["Content-Type"] = "application/json";
CString sJSON = "{\"badge\": 0}";
- PLVHTTPSocket *pSocket = new PLVHTTPNotificationSocket(&module, GetToken(), "POST", GetPushEndpoint(), mcsHeaders, sJSON);
+ PLVHTTPSocket *pSocket = new PLVHTTPNotificationSocket(&module, token, "POST", GetPushEndpoint(), mcsHeaders, sJSON);
module.AddSocket(pSocket);
m_uiBadge = 0;
}
private:
- CString m_sToken;
+ CString m_sIdentifier;
CString m_sVersion;
CString m_sPushEndpoint;
+ CString m_sPushToken;
std::map<CString, MCString> m_msmsNetworks;
pDevice->RemoveClient(*pClient);
}
- CString sToken = sLine.Token(2);
+ CString sClientIdentifier = sLine.Token(2);
CString sVersion = sLine.Token(3);
CString sNetworkID = sLine.Token(4);
- CDevice& device = DeviceWithToken(sToken);
+ CDevice& device = DeviceWithIdentifier(sClientIdentifier);
if (device.InNegotiation() == false && device.GetVersion().Equals(sVersion) == false) {
pClient->PutClient("PALAVER REQ *");
return HALT;
}
- CString sToken = sLine.Token(2);
+ CString sClientIdentifier = sLine.Token(2);
CString sVersion = sLine.Token(3);
- if (!pDevice->GetToken().Equals(sToken)) {
+ if (!pDevice->GetIdentifier().Equals(sClientIdentifier)) {
// Setting was for a different device than the one the user registered with
return HALT;
}
#pragma mark -
- CDevice& DeviceWithToken(const CString& sToken) {
+ CDevice& DeviceWithIdentifier(const CString& sIdentifier) {
CDevice *pDevice = NULL;
for (std::vector<CDevice*>::const_iterator it = m_vDevices.begin();
it != m_vDevices.end(); ++it) {
CDevice& device = **it;
- if (device.GetToken().Equals(sToken)) {
+ if (device.GetIdentifier().Equals(sIdentifier)) {
pDevice = &device;
break;
}
}
if (pDevice == NULL) {
- pDevice = new CDevice(sToken);
+ pDevice = new CDevice(sIdentifier);
m_vDevices.push_back(pDevice);
}
return pDevice;
}
- bool RemoveDeviceWithToken(const CString& sToken) {
+ bool RemoveDeviceWithIdentifier(const CString& sIdentifier) {
for (std::vector<CDevice*>::iterator it = m_vDevices.begin();
it != m_vDevices.end(); ++it) {
CDevice& device = **it;
- if (device.GetToken().Equals(sToken)) {
+ if (device.GetIdentifier().Equals(sIdentifier)) {
m_vDevices.erase(it);
Save();
return true;
const CString sNetwork = it3->first;
Table.AddRow();
- Table.SetCell("Device", device.GetToken());
+ Table.SetCell("Device", device.GetIdentifier());
Table.SetCell("User", sUsername);
Table.SetCell("Network", sNetwork);
Table.SetCell("Negotiating", CString(device.InNegotiation()));
if (networks.size() == 0) {
Table.AddRow();
- Table.SetCell("Device", device.GetToken());
+ Table.SetCell("Device", device.GetIdentifier());
Table.SetCell("User", sUsername);
Table.SetCell("Network", "");
Table.SetCell("Negotiating", CString(device.InNegotiation()));
if (msmsNetworks.size() == 0) {
Table.AddRow();
- Table.SetCell("Device", device.GetToken());
+ Table.SetCell("Device", device.GetIdentifier());
Table.SetCell("User", "");
Table.SetCell("Network", "");
Table.SetCell("Negotiating", CString(device.InNegotiation()));
CDevice *pDevice = DeviceForClient(*m_pClient);
if (pDevice) {
- PutModule("You are connected from Palaver. (" + pDevice->GetToken() + ")");
+ PutModule("You are connected from Palaver. (" + pDevice->GetIdentifier() + ")");
} else {
PutModule("You are not connected from a Palaver client.");
}
PutModule("Palaver ZNC: " + CString(PALAVER_VERSION) + " -- http://palaverapp.com/");
CDevice *pDevice = DeviceForClient(*m_pClient);
if (pDevice) {
- PutModule("Current device: (" + pDevice->GetToken() + ")");
+ PutModule("Current device: (" + pDevice->GetIdentifier() + ")");
}
PutModule(CString(m_vDevices.size()) + " registered devices");
if (status == 401) {
if (CPalaverMod *pModule = dynamic_cast<CPalaverMod *>(m_pModule)) {
DEBUG("palaver: Removing device");
- pModule->RemoveDeviceWithToken(m_sToken);
+ pModule->RemoveDeviceWithIdentifier(m_sIdentifier);
}
}
}
await tearDown(proc)
assert connected.called
+
+
+async def test_receiving_notification_with_push_token(event_loop):
+ (proc, reader, writer) = await setUp(event_loop)
+
+ async def connected(reader, writer):
+ line = await reader.readline()
+ assert line == b'POST /push HTTP/1.1\r\n'
+
+ line = await reader.readline()
+ assert line == b'Host: 127.0.0.1\r\n'
+
+ line = await reader.readline()
+ assert line == b'Authorization: Bearer abcdefg\r\n'
+
+ line = await reader.readline()
+ assert line == b'Connection: close\r\n'
+
+ line = await reader.readline()
+ assert line == b'Content-Length: 109\r\n'
+
+ line = await reader.readline()
+ assert line == b'Content-Type: application/json\r\n'
+
+ line = await reader.readline()
+ assert line == b'User-Agent: ZNC\r\n'
+
+ line = await reader.readline()
+ assert line == b'\r\n'
+
+ line = await reader.readline()
+ assert line == b'{"badge": 1,"message": "Test notification","sender": "palaver","network": "b758eaab1a4611a310642a6e8419fbff"}'
+
+ writer.write(b'HTTP/1.1 204 No Content\r\n\r\n')
+ await writer.drain()
+ writer.close()
+
+ connected.called = True
+
+ server = await asyncio.start_server(connected, host='127.0.0.1', port=0, loop=event_loop)
+ await asyncio.sleep(0.2)
+ addr = server.sockets[0].getsockname()
+ url = f'Serving on http://{addr[0]}:{addr[1]}/push'
+
+ writer.write(b'PALAVER IDENTIFY 9167e47b01598af7423e2ecd3d0a3ec4 611d3a30a3d666fc491cdea0d2e1dd6e b758eaab1a4611a310642a6e8419fbff\r\n')
+ await writer.drain()
+
+ line = await reader.readline()
+ assert line == b'PALAVER REQ *\r\n'
+
+ writer.write(b'PALAVER BEGIN 9167e47b01598af7423e2ecd3d0a3ec4 611d3a30a3d666fc491cdea0d2e1dd6e\r\n')
+ writer.write(f'PALAVER SET PUSH-ENDPOINT {url}\r\n'.encode('utf-8'))
+ writer.write(f'PALAVER SET PUSH-TOKEN abcdefg\r\n'.encode('utf-8'))
+ writer.write(b'PALAVER END\r\n')
+ await writer.drain()
+
+ writer.write(b'PRIVMSG *palaver :test\r\n')
+ await writer.drain()
+
+ await asyncio.sleep(0.2)
+ server.close()
+ await server.wait_closed()
+
+ await tearDown(proc)
+
+ assert connected.called