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

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