1
0
Fork 0
mirror of https://github.com/HackHerz/pusher synced 2025-12-06 02:10:19 +00:00

First commit

This commit is contained in:
Daniel Stein 2014-09-11 14:16:50 +02:00
commit b403801750
6 changed files with 571 additions and 0 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
# executable
pusher
# makefile
makefile

13
LICENSE Normal file
View file

@ -0,0 +1,13 @@
Copyright (c) 2014 HackHerz
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3) If you modify the source in any way, you have to remove the authors PushNotifier API-token and replace it with your own. It is the same for the package-name.
4) You have to make sure that the modified program doesn't break the PushNotifer API rules.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

20
README.md Normal file
View file

@ -0,0 +1,20 @@
# pusher
Pusher is a program to notify you.
# Building
## Requirements
* boost
* curl
## Compile
# Usage
# Documentation

242
src/main.cpp Normal file
View file

@ -0,0 +1,242 @@
/*
* pusher
* (c) 2014 Daniel Stein
* github link..
*
* TODO
* syslog
* content type detection
* gitignore of lines
* secret input of password
*/
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
// Boost
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
// own header files
#include "pushhandler.h"
#define CONFIG_FILE "/etc/pusher.conf"
// namespaces
using namespace std;
namespace po = boost::program_options;
// number of digit
int numDigits(int number)
{
int digits = 0;
while(number != 0)
{
number /= 10;
digits++;
}
return digits;
}
// main
int main(int argc, char **argv)
{
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "Print help message")
("token,t", "Request your token") // TODO
("list,l", "List of all your devices") // TODO
("pipe,p", "Input via pipe") // TODO
("quiet,q", "Outputs are redirected to syslog") // TODO
("verify,v", "Checks if token is still valid") // TODO
("id,i", po::value<int>(), "Specify device ID"); // TODO
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
try
{
string message;
int id;
// help
if(vm.count("help"))
{
cout << desc << endl;
return 0;
}
// request token
if(vm.count("token"))
{
//request token
string username, password, token;
cout << "Username: ";
cin >> username;
cout << "Password: ";
cin >> password;
PushHandler buf(username);
token = buf.login(password);
// generate config file
stringstream conffile;
conffile << boost::format("[pusher]\nusername=%1%\nappToken=%2%")
% username
% token;
// attempt to save token
ofstream dat_aus;
dat_aus.open(CONFIG_FILE, ios_base::out);
if(!dat_aus.is_open())
{
cout << "Try running pusher as root or save the following in " << CONFIG_FILE << "\n" << endl;
cout << conffile.str() << endl;
return 1;
}
// save
dat_aus << conffile.str();
dat_aus.close();
return 0;
}
// load conf and check if token is specified
boost::property_tree::ptree pt;
boost::property_tree::ini_parser::read_ini(CONFIG_FILE, pt);
string username = pt.get<std::string>("pusher.username");
string appToken = pt.get<std::string>("pusher.appToken");
// loading values
PushHandler pusherInstance(username, appToken);
// verify token
if(vm.count("verify"))
{
if(pusherInstance.verifyToken())
{
cout << "appToken is valid" << endl;
return 0;
}
else
{
cout << "appToken is invalid" << endl;
return 1;
}
}
// list devices
if(vm.count("list"))
{
vector<PushHandler::Device> devices;
devices = pusherInstance.getDevices();
int titleLength = 5;
int modelLength = 5;
int idLength = 2;
for(int i = 0; i < devices.size(); i++)
{
if(devices[i].title.length() > titleLength) { titleLength = devices[i].title.length(); }
if(devices[i].model.length() > modelLength) { modelLength = devices[i].model.length(); }
if(numDigits(devices[i].id) > idLength) { idLength = numDigits(devices[i].id); }
}
cout
<< "ID\033[" << (idLength - 2 + 2) << "C"
<< "Title\033[" << (titleLength - 5 + 2) << "C"
<< "Model" << endl;
for(int x = 0; x < (titleLength + modelLength + idLength + 4); x++) { cout << "-"; }
cout << endl;
for(int i = 0; i < devices.size(); i++)
{
cout
<< devices[i].id << "\033[" << (idLength - numDigits(devices[i].id) + 2) << "C"
<< devices[i].title << "\033[" << (titleLength - devices[i].title.length() + 2) << "C"
<< devices[i].model << endl;
}
return 0;
}
// device id
if(vm.count("id"))
{
id = vm["id"].as<int>();
}
else
{
cout << desc << endl;
return 1;
}
// load message
if(vm.count("pipe"))
{
message = "pipe";
}
else
{
stringstream lastArgument;
lastArgument << argv[argc-1];
message = lastArgument.str();
cout << message << endl;
}
// send the message
pusherInstance.sendToDevice(id, message);
}
/* ERROR HANDLING */
// errors thrown by pushhandler
catch(PusherError& e)
{
cout << "Error: " << e.what() << endl;
}
// boos ptree
catch(const boost::property_tree::ptree_error &e)
{
cout << "Maybe you need to request your appToken first?\n" << endl;
cout << e.what() << "\n" << desc << endl;
}
// other errors
catch(exception& e)
{
cout << "Some kind of error occured: " << e.what() << endl;
}
return 0;
}

232
src/pushhandler.cpp Normal file
View file

@ -0,0 +1,232 @@
#include "pushhandler.h"
#include <sstream>
#include <curl/curl.h>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
using namespace std;
// needed for handling curl output
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
// curl wrapper
string curlHandler(string data, const char* url)
{
CURL *curl;
CURLcode res;
string readBuffer;
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(res != CURLE_OK)
{
throw PusherError("Network Error");
}
}
return readBuffer;
}
// constructor only username
PushHandler::PushHandler(string username)
{
this->username = username;
}
// constructor with appToken
PushHandler::PushHandler(string username, string appToken)
{
this->username = username;
this->appToken = appToken;
}
// login
string PushHandler::login(string password)
{
// build request data
stringstream requestData;
requestData << boost::format("apiToken=%1%&username=%2%&password=%3%")
% API_TOKEN
% this->username
% password;
// network request
string readBuffer;
readBuffer = curlHandler(requestData.str(), URL_PN_LOGIN);
// json parsing
stringstream jsonData;
jsonData << readBuffer;
boost::property_tree::ptree pt;
boost::property_tree::read_json(jsonData, pt);
if(pt.get<string>("status") != "ok")
{
throw PusherError("wrong credentials");
}
this->appToken = pt.get<string>("appToken");
return this->appToken;
}
// get list of devices
vector<PushHandler::Device> PushHandler::getDevices()
{
// build request data
stringstream requestData;
requestData << boost::format("apiToken=%1%&appToken=%2%")
% API_TOKEN
% this->appToken;
// network request
string readBuffer;
readBuffer = curlHandler(requestData.str(), URL_PN_GET_DEVICES);
// json parsing
stringstream jsonData;
jsonData << readBuffer;
boost::property_tree::ptree pt;
boost::property_tree::read_json(jsonData, pt);
// handle the codes
switch(pt.get<int>("code"))
{
case 1: throw PusherError("Invalid API Token");
break;
case 2: throw PusherError("App Token missing");
break;
case 3: throw PusherError("App Token invalid");
}
vector<Device> buffer;
BOOST_FOREACH(boost::property_tree::ptree::value_type& v, pt.get_child("devices"))
{
Device buf;
buf.title = v.second.get<string>("title");
buf.id = v.second.get<int>("id");
buf.model = v.second.get<string>("model");
buffer.push_back(buf);
}
return buffer;
}
// verify token
bool PushHandler::verifyToken()
{
// build request data
stringstream requestData;
requestData << boost::format("apiToken=%1%&username=%2%&appToken=%3%")
% API_TOKEN
% this->username
% this->appToken;
// network request
string readBuffer;
readBuffer = curlHandler(requestData.str(), URL_PN_CHECK_TOKEN);
// json parser
stringstream jsonData;
jsonData << readBuffer;
boost::property_tree::ptree pt;
boost::property_tree::read_json(jsonData, pt);
switch(pt.get<int>("code"))
{
case 0: return true;
break;
case 1: throw PusherError("Invalid API-Token");
break;
case 2: return false;
default: throw PusherError("Invalid server response");
}
}
// send to device
void PushHandler::sendToDevice(int id, string message)
{
// analyze content-type
// ......
// actual sending
// build request data
stringstream requestData;
requestData << boost::format("apiToken=%1%&appToken=%2%&app=%3%&deviceID=%4%&type=%5%&content=%6%")
% API_TOKEN
% this->appToken
% APP_PACKAGE
% id
% "MESSAGE"
% message;
// network request
string readBuffer;
readBuffer = curlHandler(requestData.str(), URL_PN_SEND_TO_DEVICE);
// json parsing
stringstream jsonData;
jsonData << readBuffer;
boost::property_tree::ptree pt;
boost::property_tree::read_json(jsonData, pt);
switch(pt.get<int>("id"))
{
case 0: //return 0;
break;
case 1: throw PusherError("Invalid API Token");
break;
case 2: throw PusherError("App Token missing");
break;
case 3: throw PusherError("App Token invalid");
break;
case 4: throw PusherError("Package Name missing");
break;
case 5: throw PusherError("Package Name invalid");
break;
case 6: throw PusherError("Package Name is not linked with the provided API Token");
break;
case 7: throw PusherError("Device ID missing");
break;
case 8: throw PusherError("Device ID invalid");
break;
case 9: throw PusherError("Type missing or invalid");
break;
default: throw PusherError("Invalid server response");
}
}

59
src/pushhandler.h Normal file
View file

@ -0,0 +1,59 @@
#ifndef H_PUSHHANDLER
#define H_PUSHHANDLER
#include <string>
#include <vector>
#define API_TOKEN "1234" // change this line
#define APP_PACKAGE "com.hackherz.pusher"
#define USER_AGENT "pusher/0.2"
#define URL_PN_LOGIN "http://a.pushnotifier.de/1/login/"
#define URL_PN_CHECK_TOKEN "http://a.pushnotifier.de/1/checkToken/"
#define URL_PN_GET_DEVICES "http://a.pushnotifier.de/1/getDevices/"
#define URL_PN_SEND_TO_DEVICE "http://a.pushnotifier.de/1/sendToDevice/"
class PushHandler
{
public:
PushHandler(std::string username);
PushHandler(std::string username, std::string appToken);
typedef struct
{
std::string title;
int id;
std::string model;
} Device;
std::string login(std::string password);
std::vector<Device> getDevices();
void sendToDevice(int deviceID, std::string message);
bool verifyToken();
private:
std::string username;
std::string appToken;
};
// class for exceptions
class PusherError
{
public:
PusherError(std::string content) { this->content = content; }
std::string what() { return this->content; }
private:
std::string content;
};
#endif