V1.3 Senden von Nachrichten und Dateien funktioniert

This commit is contained in:
2022-08-13 17:27:26 +02:00
parent ba6959ce21
commit d9caa116e2
2 changed files with 524 additions and 112 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
_login response.txt
Dirk.py
test.txt

View File

@@ -1,134 +1,544 @@
<?php
/*
Nenninger N-Tools.de
Version 1.1
Version 1.3
braucht curl und php > 8.1
hermine@THW PHPConnector
inspiriert von https://gitlab.com/aeberhardt/stashcat-api-client
Beispiel:
$hermine = new hermineConnect('mailadresse','Accountpassword','Verschlüsselungskennwort');
if($hermine->login(true) !== false){
$array = $hermine->get_companies_list();
print_r($array);
$array = $hermine->get_conversations_list();
print_r($array);
$array = $hermine->get_channels_list();
print_r($array);
$file = file_get_contents('./ich.jpg');
$hermine->send_message_with_file_to_channel(165562,'jpg per php',$file,'test.jpg','image/jpeg',1080,2068);
send_message_to_conversation(id,message);
send_message_to_channel(id,message);
}else{
//login fehlgeschlagen
print_r($hermine->lasterror);
}
*/
class UUID {
public static function v3($namespace, $name) {
if(!self::is_valid($namespace)) return false;
// Get hexadecimal components of namespace
$nhex = str_replace(array('-','{','}'), '', $namespace);
// Binary Value
$nstr = '';
// Convert Namespace UUID to bits
for($i = 0; $i < strlen($nhex); $i+=2) {
$nstr .= chr(hexdec($nhex[$i].$nhex[$i+1]));
}
// Calculate hash value
$hash = md5($nstr . $name);
return sprintf('%08s-%04s-%04x-%04x-%12s',
// 32 bits for "time_low"
substr($hash, 0, 8),
// 16 bits for "time_mid"
substr($hash, 8, 4),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 3
(hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x3000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
(hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
// 48 bits for "node"
substr($hash, 20, 12)
);
}
public static function v4() {
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
// 16 bits for "time_mid"
mt_rand(0, 0xffff),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand(0, 0x0fff) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand(0, 0x3fff) | 0x8000,
// 48 bits for "node"
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
public static function v5($namespace, $name) {
if(!self::is_valid($namespace)) return false;
// Get hexadecimal components of namespace
$nhex = str_replace(array('-','{','}'), '', $namespace);
// Binary Value
$nstr = '';
// Convert Namespace UUID to bits
for($i = 0; $i < strlen($nhex); $i+=2) {
$nstr .= chr(hexdec($nhex[$i].$nhex[$i+1]));
}
// Calculate hash value
$hash = sha1($nstr . $name);
return sprintf('%08s-%04s-%04x-%04x-%12s',
// 32 bits for "time_low"
substr($hash, 0, 8),
// 16 bits for "time_mid"
substr($hash, 8, 4),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 5
(hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x5000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
(hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
// 48 bits for "node"
substr($hash, 20, 12)
);
}
public static function is_valid($uuid) {
return preg_match('/^\{?[0-9a-f]{8}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?'.
'[0-9a-f]{4}\-?[0-9a-f]{12}\}?$/i', $uuid) === 1;
}
}
class hermineConnect{
private $hermineServer = 'https://api.thw-messenger.de';
//private $hermineServer = 'https://thw.n-tools.de';
private $connectorID = "";
private $user = "";
private $password = "";
private $passphrase = "";
private $cURL;
private $client_key = "";
private $user_id = "";
private $VERSION = '1.3';
private $hermineServer = 'https://api.thw-messenger.de';
//private $hermineServer = 'https://thw.n-tools.de';
private $connectorID = "";
private $user = "";
private $password = "";
private $passphrase = "";
private $cURL;
private $client_key = "";
private $user_id = "";
private $private_key;
private $key_cache_channels;
private $key_cache_conversations;
private $lasterror;
private $companies;
private $channels;
private $conversations;
//private $debug = true;
function build_data_files($boundary, $fields, $files){
$data = '';
$eol = "\r\n";
function __construct($user,$password,$passphrase) {
$this->connectorID = base64_encode('deadbeef'.sha1($_SERVER['SERVER_NAME']));
$this->user = $user;
$this->password = $password;
$this->passphrase = $passphrase;
$this->cURL = curl_init();
}
function __destruct() {
curl_close($this->cURL);
}
function request($_url,$_data){
$_data['device_id'] = $this->connectorID;
if($this->client_key != '')
$_data['client_key'] = $this->client_key;
print_r($_data);
curl_setopt($this->cURL, CURLOPT_URL, $_url);
//curl_setopt($this->cURL, CURLOPT_PORT , 443);
curl_setopt($this->cURL, CURLOPT_VERBOSE, 0);
//curl_setopt($this->cURL, CURLOPT_HEADER, 0);
//curl_setopt($this->cURL, CURLOPT_SSLVERSION, 3);
//curl_setopt($this->cURL, CURLOPT_SSLCERT, getcwd() . "/client.pem");
//curl_setopt($this->cURL, CURLOPT_SSLKEY, getcwd() . "/keyout.pem");
//curl_setopt($this->cURL, CURLOPT_CAINFO, getcwd() . "/ca.pem");
curl_setopt($this->cURL, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($this->cURL, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->cURL, CURLOPT_POST, true);
//curl_setopt($this->cURL, CURLOPT_BINARYTRANSFER, true);
curl_setopt($this->cURL, CURLOPT_POSTFIELDS,$_data);
curl_setopt($this->cURL, CURLOPT_HTTPHEADER, array("Accept: application/json, text/plain, */*","Connection: keep-alive","Keep-Alive: timeout=5, max=100"));
curl_setopt( $this->cURL, CURLOPT_COOKIESESSION, true );
curl_setopt( $this->cURL, CURLOPT_COOKIEJAR, './hermineConnectCookie.txt' );
curl_setopt( $this->cURL, CURLOPT_COOKIEFILE, './hermineConnectCookie.txt' );
$data = curl_exec($this->cURL);
if(!curl_errno($this->cURL)){
$data = json_decode($data);
if($data->status->value != "OK")
print_r($data);
$info = curl_getinfo($this->cURL);
return $data->payload;// 'Took ' . $info['total_time'] . ' seconds to send a request to ' . $info['url'];
} else {
return false; //echo 'Curl error: ' . curl_error($cURL);
}
}
function open_private_key(){
$data = [];
$response = $this->request($this->hermineServer."/security/get_private_key",$data);
print_r($response->keys->private_key);
//$privkey_decoded = @openssl_pkey_get_private($private_key, $this->passphrase);
}
/*open_private_key(self, encryption_password):
data = self._post("security/get_private_key", data={})
private_key_field = json.loads(data["keys"]["private_key"])
# there might be an unescaping bug here....
self.private_key = Crypto.PublicKey.RSA.import_key(
private_key_field["private"], passphrase=encryption_password
) */
$delimiter = '-------------' . $boundary;
public function getID(){
return $this->connectorID;
}
public function login(){
$data = [
"email" => $this->user,
"password" => $this->password,
"app_name" => 'hermine@thw-php:1.1-browser-0',
"encrypted" => true,
"callable" => true
];
$response = $this->request($this->hermineServer."/auth/login",$data);
if($response !== false){
$this->client_key = $response->client_key;
$this->user_id = $response->userinfo->id;
$this->open_private_key();
return $response;
}
foreach ($fields as $name => $content) {
$data .= "--" . $delimiter . $eol
. 'Content-Disposition: form-data; name="' . $name . "\"".$eol.$eol
. $content . $eol;
}
public function get_companies(){
$data = [
"no_cache" => true
];
$response = $this->request($this->hermineServer."/company/member",$data);
if($response !== false){
return $response;
}else{
return false;
}
foreach ($files as $name => $content) {
$data .= "--" . $delimiter . $eol
. 'Content-Disposition: form-data; name="file"; filename="[object Object]"' . $eol
. 'Content-Type: application/octet-stream'.$eol
//. 'Content-Transfer-Encoding: binary'.$eol
;
$data .= $eol;
$data .= $content . $eol;
}
$data .= "--" . $delimiter . "--".$eol;
return $data;
}
function __construct($user,$password,$passphrase) {
function intArrayToString($ia){
$ret = '';
foreach($ia as $val){
$ret .= chr($val);
}
return $ret;
}
$cID = array_map('hexdec', str_split('deadbeef'.sha1($_SERVER['SERVER_NAME']), 2));
$cID = intArrayToString($cID);
$this->connectorID = base64_encode($cID);
$this->user = $user;
$this->password = $password;
$this->passphrase = $passphrase;
$this->cURL = curl_init();
}
function __destruct() {
curl_close($this->cURL);
}
function request($_url,$_data,$_files=[]){
$_data['device_id'] = $this->connectorID;
if($this->client_key != '')
$_data['client_key'] = $this->client_key;
$boundary = uniqid();
$delimiter = '-------------' . $boundary;
$_data = $this->build_data_files($boundary, $_data, $_files);
curl_setopt($this->cURL, CURLOPT_URL, $_url);
curl_setopt($this->cURL, CURLOPT_VERBOSE, 0);
curl_setopt($this->cURL, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($this->cURL, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->cURL, CURLOPT_POST, true);
curl_setopt($this->cURL, CURLOPT_POSTFIELDS,$_data);
curl_setopt($this->cURL, CURLOPT_HTTPHEADER, array("Accept: application/json, text/plain, */*",
"Keep-Alive: timeout=5, max=100",
"Connection: keep-alive",
"Content-Type: multipart/form-data; boundary=" . $delimiter,
"Content-Length: " . strlen($_data),
'Expect:'
));
curl_setopt( $this->cURL, CURLOPT_COOKIESESSION, true );
curl_setopt( $this->cURL, CURLOPT_COOKIEJAR, './hermineConnectCookie.txt' );
curl_setopt( $this->cURL, CURLOPT_COOKIEFILE, './hermineConnectCookie.txt' );
curl_setopt( $this->cURL, CURLINFO_HEADER_OUT, true);
if(isset($this->debug))
echo "\n\nsenddata->:\n".print_r($_data,true);
$data = curl_exec($this->cURL);
if(!curl_errno($this->cURL)){
if(isset($this->debug)){
echo "\n\nretdata->:\n".print_r($data,true);
echo "\n\nSendheader->:\n".print_r(curl_getinfo($this->cURL, CURLINFO_HEADER_OUT),true);
}
$data = json_decode($data);
if($data->status->value === "OK"){
$this->lasterror = '';
return $data->payload;
}else{
$this->lasterror = $data;
return false;
}
} else {
$this->lasterror = 'Curl error: ' . curl_error($cURL);
return false;
}
}
function _open_private_key(){
$data = [];
$response = $this->request($this->hermineServer."/security/get_private_key",$data);
$private_key = json_decode($response->keys->private_key);
$privkey_decoded = openssl_pkey_get_private($private_key->private, $this->passphrase);
if($privkey_decoded !== false){
$this->private_key = $privkey_decoded;
return true;
}else{
return false;
}
}
function _get_conversation_key($_target){
if($_target[0]=='conversation'){
if(!isset($this->key_cache_conversations[$_target[1]])){
$data = [ "conversation_id" => $_target[1]
];
$response = $this->request($this->hermineServer."/message/conversation",$data);
$this->key_cache_conversations[$_target[1]] = $response->conversation->key;
}
if(openssl_private_decrypt(base64_decode($this->key_cache_conversations[$_target[1]]),$ret,$this->private_key,OPENSSL_PKCS1_OAEP_PADDING))
return $ret;
else
return false;
}else if($_target[0]=='channel'){
if(!isset($this->key_cache_channels[$_target[1]])){
$data = [ "channel_id" => $_target[1],
"without_members" => true
];
$response = $this->request($this->hermineServer."/channels/info",$data);
$this->key_cache_channels[$_target[1]] = $response->channels->key;
}
if(openssl_private_decrypt(base64_decode($this->key_cache_channels[$_target[1]]),$ret,$this->private_key,OPENSSL_PKCS1_OAEP_PADDING))
return $ret;
else
return false;
}
}
function _encrypt_aes($_plain, $_key, $_iv){
$ret = openssl_encrypt($_plain, "AES-256-CBC", $_key, 0, $_iv);
print_r($ret);
return $ret;
}
$test = new hermineConnect('xxx@n4h.de','xxx','xxxx');
echo $test->getID();
$test->login();
print_r($test);
//print_r($test->get_companies());
public function getLastError(){
return $this->lasterror;
}
public function getID(){
return $this->connectorID;
}
public function login($_saveLogin=false){
if($_saveLogin){
if(file_exists('./login.dat')){
$savelogin = json_decode(file_get_contents('./login.dat'));
$this->client_key = $savelogin->ClientKey;
$this->connectorID = $savelogin->DeviceId;
$this->user_id = $savelogin->UserID;
if($this->_open_private_key()){
$this->companies = $this->get_companies();
$this->channels = $this->get_channels($this->companies->companies[0]->id);
$this->conversations = $this->get_conversations();
return true;
}
}
}
$data = [
"email" => $this->user,
"password" => $this->password,
"app_name" => 'hermine@thw-PHP:'.$this->VERSION,
"encrypted" => true,
"callable" => false
];
$response = $this->request($this->hermineServer."/auth/login",$data);
if($response !== false){
$this->client_key = $response->client_key;
$this->user_id = $response->userinfo->id;
if($this->_open_private_key()){
$this->companies = $this->get_companies();
$this->channels = $this->get_channels($this->companies->companies[0]->id);
$this->conversations = $this->get_conversations();
if($_saveLogin){
$savelogin['ClientKey'] = $this->client_key;
$savelogin['DeviceId'] = $this->connectorID;
$savelogin['UserID'] = $this->user_id;
file_put_contents('./login.dat',json_encode($savelogin));
}
return true;
}
}
return false;
}
function get_companies(){
$data = [
"no_cache" => true
];
$response = $this->request($this->hermineServer."/company/member",$data);
if($response !== false){
return $response;
}else{
return false;
}
}
function get_conversations($_limit = 99999, $_offset = 0){
$data = [
"limit" => $_limit,
"offset" => true,
"archive" => 0
];
$response = $this->request($this->hermineServer."/message/conversations",$data);
if($response !== false){
return $response;
}else{
return false;
}
}
function get_channels($_company_id){
$data = [
"no_cache" => true,
"company" => $_company_id
];
$response = $this->request($this->hermineServer."/channels/subscripted",$data);
if($response !== false){
return $response;
}else{
return false;
}
}
public function get_companies_list(){
$ret = [];
foreach($this->companies->companies as $company){
$ret[$company->id] = $company->name;
}
return $ret;
}
public function get_conversations_list(){
$ret = [];
foreach($this->conversations->conversations as $conversation){
$ret[$conversation->id] = $conversation->members[0]->last_name;
}
return $ret;
}
public function get_channels_list(){
$ret = [];
foreach($this->channels->channels as $channels){
$ret[$channels->id] = $channels->name;
}
return $ret;
}
function sendmsg($_target,$_message,$_files=[],$_location=false,$_encrypted=true){
$iv = openssl_random_pseudo_bytes(16);
$conversation_key = $this->_get_conversation_key($_target);
$data = [
"target" => $_target[0],
$_target[0]."_id" => $_target[1],
"text" => bin2hex(base64_decode($this->_encrypt_aes($_message, $conversation_key, $iv))),
"iv" => bin2hex($iv),
"files" => json_encode($_files), //Nummern vom Upload!
"url" => "[]",
"type" => "text",
"verification" => "",
"encrypted" => true
];
if(!$_encrypted){
$data['encrypted'] = false;
$data['text'] = $_message;
unset($data[$iv]);
}
if($_location !== false){
if(!$_encrypted){
}
}
print_r($data);
$response = $this->request($this->hermineServer."/message/send",$data);
if($response !== false){
return $response;
}else{
return false;
}
}
//function uploadfile($_target,$_filerawdatat,$_filename,$_content_type="application/octet-stream",$_media_size=NULL,$_encrypted=false){
function uploadfile($_target,$_fileraw,$_filename,$_filetype,$_mediawidth=0,$_mediaheight=0){
$iv = openssl_random_pseudo_bytes(16);
$file_key = openssl_random_pseudo_bytes(32);
//$file = file_get_contents($_filewithpath);
$file_uuid = UUID::v4();
$chunk_size = 5 * 1024 * 1024;
$filesize = strlen($_fileraw);
//$file = new \CURLStringFile($_fileraw, $_filename, $_filetype);
$file_encryptet = base64_decode($this->_encrypt_aes($_fileraw, $file_key, $iv));
$file = ['dummy' => $file_encryptet];
$data = [
"resumableChunkNumber" => 0,
"resumableChunkSize" => $chunk_size,
"resumableCurrentChunkSize" => strlen($file_encryptet),
"resumableTotalSize" => $filesize,
"resumableType" => $_filetype,
"resumableIdentifier" => $file_uuid,
"resumableFilename" => $_filename,
"resumableRelativePath" => $_filename,
"resumableTotalChunks" => 1,
"folder" => 0,
"media_width" => $_mediawidth,
"media_height" => $_mediaheight,
"iv" => bin2hex($iv),
"type" => $_target[0],
"type_id" => $_target[1],
"encrypted" => true
];
$response = $this->request($this->hermineServer."/file/upload",$data,$file);
if($response !== false){
$iv = openssl_random_pseudo_bytes(16);
$conversation_key = $this->_get_conversation_key($_target);
$fileid = $response->file->id;
$data = [
"file_id" => $fileid,
"target" => $_target[0],
"target_id" => $_target[1],
"iv" => bin2hex($iv),
"key" => bin2hex(base64_decode($this->_encrypt_aes($file_key, $conversation_key, $iv)))
];
$response = $this->request($this->hermineServer."/security/set_file_access_key",$data);
return $fileid;
}else{
return false;
}
}
public function send_message_to_conversation($_conversation_id,$_message){
return $this->sendmsg(array('conversation',$_conversation_id),$_message);
}
public function send_message_with_file_to_conversation($_conversation_id,$_message,$_fileraw,$_filename,$_filetype,$_mediawidth=0,$_mediaheight=0){
$ret = $this->uploadfile(array('conversation',$_conversation_id),$_fileraw,$_filename,$_filetype,$_mediawidth,$_mediaheight);
return $this->sendmsg(array('conversation',$_conversation_id),$_message,[$ret]);
}
public function send_message_to_channel($_channel_id,$_message){
return $this->sendmsg(array('channel',$_channel_id),$_message);
}
public function send_message_with_file_to_channel($_channel_id,$_message,$_fileraw,$_filename,$_filetype,$_mediawidth=0,$_mediaheight=0){
$ret = $this->uploadfile(array('channel',$_channel_id),$_fileraw,$_filename,$_filetype,$_mediawidth,$_mediaheight);
return $this->sendmsg(array('channel',$_channel_id),$_message,[$ret]);
}
}
?>